mysql.cc 92.4 KB
Newer Older
1
/* Copyright (C) 2000-2003 MySQL AB
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
7

bk@work.mysql.com's avatar
bk@work.mysql.com committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
12

bk@work.mysql.com's avatar
bk@work.mysql.com committed
13 14 15 16 17 18 19 20 21
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/* mysql command tool
 * Commands compatible with mSQL by David J. Hughes
 *
 * Written by:
 *   Michael 'Monty' Widenius
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
22 23 24 25 26 27
 *   Andi Gutmans  <andi@zend.com>
 *   Zeev Suraski  <zeev@zend.com>
 *   Jani Tolonen  <jani@mysql.com>
 *   Matt Wagner   <matt@mysql.com>
 *   Jeremy Cole   <jcole@mysql.com>
 *   Tonu Samuel   <tonu@mysql.com>
28
 *   Harrison Fisk <harrison@mysql.com>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
29 30 31
 *
 **/

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
32
#include "client_priv.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
33
#include <m_ctype.h>
34
#include <stdarg.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
35 36
#include <my_dir.h>
#ifndef __GNU_LIBRARY__
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
37
#define __GNU_LIBRARY__		      // Skip warnings in getopt.h
bk@work.mysql.com's avatar
bk@work.mysql.com committed
38 39 40
#endif
#include "my_readline.h"
#include <signal.h>
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
41
#include <violite.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
42

43 44 45 46
#if defined(USE_LIBEDIT_INTERFACE) && defined(HAVE_LOCALE_H)
#include <locale.h>
#endif

47
const char *VER= "14.10";
48

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
49 50 51
/* Don't try to make a nice table if the data is too big */
#define MAX_COLUMN_LENGTH	     1024

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
52
gptr sql_alloc(unsigned size);	     // Don't use mysqld alloc for these
bk@work.mysql.com's avatar
bk@work.mysql.com committed
53 54 55 56 57 58 59 60 61 62 63 64 65 66
void sql_element_free(void *ptr);
#include "sql_string.h"

extern "C" {
#if defined(HAVE_CURSES_H) && defined(HAVE_TERM_H)
#include <curses.h>
#include <term.h>
#else
#if defined(HAVE_TERMIOS_H)
#include <termios.h>
#include <unistd.h>
#elif defined(HAVE_TERMBITS_H)
#include <termbits.h>
#elif defined(HAVE_ASM_TERMBITS_H) && (!defined __GLIBC__ || !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ > 0))
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
67
#include <asm/termbits.h>		// Standard linux
bk@work.mysql.com's avatar
bk@work.mysql.com committed
68 69 70 71 72 73 74 75
#endif
#undef VOID
#if defined(HAVE_TERMCAP_H)
#include <termcap.h>
#else
#ifdef HAVE_CURSES_H
#include <curses.h>
#endif
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
76
#undef SYSV				// hack to avoid syntax error
bk@work.mysql.com's avatar
bk@work.mysql.com committed
77 78 79 80 81 82
#ifdef HAVE_TERM_H
#include <term.h>
#endif
#endif
#endif

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
83
#undef bcmp				// Fix problem with new readline
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
84
#if defined( __WIN__) || defined(OS2)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
85
#include <conio.h>
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
86
#elif !defined(__NETWARE__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
87 88 89 90 91 92 93 94
#include <readline/readline.h>
#define HAVE_READLINE
#endif
  //int vidattr(long unsigned int attrs);	// Was missing in sun curses
}

#if !defined(HAVE_VIDATTR)
#undef vidattr
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
95
#define vidattr(A) {}			// Can't get this to work
bk@work.mysql.com's avatar
bk@work.mysql.com committed
96 97
#endif

98
#ifdef FN_NO_CASE_SENCE
99
#define cmp_database(cs,A,B) my_strcasecmp((cs), (A), (B))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
100
#else
101
#define cmp_database(cs,A,B) strcmp((A),(B))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
102 103
#endif

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
104 105 106 107
#if !defined( __WIN__) && !defined( OS2) && !defined(__NETWARE__) && (!defined(HAVE_mit_thread) || !defined(THREAD))
#define USE_POPEN
#endif

bk@work.mysql.com's avatar
bk@work.mysql.com committed
108 109
#include "completion_hash.h"

jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
110
#define PROMPT_CHAR '\\'
111
#define DEFAULT_DELIMITER ";"
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
112

bk@work.mysql.com's avatar
bk@work.mysql.com committed
113 114 115 116 117 118 119 120 121 122 123
typedef struct st_status
{
  int exit_status;
  ulong query_start_line;
  char *file_name;
  LINE_BUFFER *line_buff;
  bool batch,add_to_history;
} STATUS;


static HashTable ht;
124
static char **defaults_argv;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
125 126 127 128 129

enum enum_info_type { INFO_INFO,INFO_ERROR,INFO_RESULT};
typedef enum enum_info_type INFO_TYPE;

static MYSQL mysql;			/* The connection */
130 131
static my_bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0,
               connected=0,opt_raw_data=0,unbuffered=0,output_tables=0,
132
	       rehash=1,skip_updates=0,safe_updates=0,one_database=0,
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
133
	       opt_compress=0, using_opt_local_infile=0,
134 135
	       vertical=0, line_numbers=1, column_names=1,opt_html=0,
               opt_xml=0,opt_nopager=1, opt_outfile=0, named_cmds= 0,
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
136
	       tty_password= 0, opt_nobeep=0, opt_reconnect=1,
137
	       default_charset_used= 0, opt_secure_auth= 0,
138
               default_pager_set= 0, opt_sigint_ignore= 0;
139
static ulong opt_max_allowed_packet, opt_net_buffer_length;
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
140
static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
141 142 143
static my_string opt_mysql_unix_port=0;
static int connect_flag=CLIENT_INTERACTIVE;
static char *current_host,*current_db,*current_user=0,*opt_password=0,
144
            *current_prompt=0, *delimiter_str= 0,
145
            *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
146
static char *histfile;
147
static char *histfile_tmp;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
148
static String glob_buffer,old_buffer;
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
149 150
static String processed_prompt;
static char *full_username=0,*part_username=0,*default_prompt=0;
151
static int wait_time = 5;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
152
static STATUS status;
153
static ulong select_limit,max_join_size,opt_connect_timeout=0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
154
static char mysql_charsets_dir[FN_REFLEN+1];
155
static const char *xmlmeta[] = {
156 157
  "&", "&amp;",
  "<", "&lt;",
158 159
  ">", "&gt;",
  "\"", "&quot;",
160 161
  0, 0
};
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
162 163 164 165 166 167 168 169
static const char *day_names[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
static const char *month_names[]={"Jan","Feb","Mar","Apr","May","Jun","Jul",
			    "Aug","Sep","Oct","Nov","Dec"};
static char default_pager[FN_REFLEN];
static char pager[FN_REFLEN], outfile[FN_REFLEN];
static FILE *PAGER, *OUTFILE;
static MEM_ROOT hash_mem_root;
static uint prompt_counter;
170 171
static char delimiter[16]= DEFAULT_DELIMITER;
static uint delimiter_length= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
172

173 174 175 176
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
#endif
static uint opt_protocol=0;
177
static CHARSET_INFO *charset_info= &my_charset_latin1;
178

bk@work.mysql.com's avatar
bk@work.mysql.com committed
179 180 181 182
#include "sslopt-vars.h"

const char *default_dbug_option="d:t:o,/tmp/mysql.trace";

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
183 184 185
void tee_fprintf(FILE *file, const char *fmt, ...);
void tee_fputs(const char *s, FILE *file);
void tee_puts(const char *s, FILE *file);
186
void tee_putc(int c, FILE *file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
187 188 189 190
/* The names of functions that actually do the manipulation. */
static int get_options(int argc,char **argv);
static int com_quit(String *str,char*),
	   com_go(String *str,char*), com_ego(String *str,char*),
191
	   com_print(String *str,char*),
bk@work.mysql.com's avatar
bk@work.mysql.com committed
192 193 194
	   com_help(String *str,char*), com_clear(String *str,char*),
	   com_connect(String *str,char*), com_status(String *str,char*),
	   com_use(String *str,char*), com_source(String *str, char*),
195
	   com_rehash(String *str, char*), com_tee(String *str, char*),
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
196
           com_notee(String *str, char*),
197
           com_prompt(String *str, char*), com_delimiter(String *str, char*);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
198

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
199
#ifdef USE_POPEN
200
static int com_nopager(String *str, char*), com_pager(String *str, char*),
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
201
           com_edit(String *str,char*), com_shell(String *str, char *);
202 203
#endif

bk@work.mysql.com's avatar
bk@work.mysql.com committed
204 205 206
static int read_lines(bool execute_commands);
static int sql_connect(char *host,char *database,char *user,char *password,
		       uint silent);
207 208 209
static int put_info(const char *str,INFO_TYPE info,uint error=0,
		    const char *sql_state=0);
static int put_error(MYSQL *mysql);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
210
static void safe_put_field(const char *pos,ulong length);
211
static void xmlencode_print(const char *src, uint length);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
212 213
static void init_pager();
static void end_pager();
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
214
static void init_tee(const char *);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
215
static void end_tee();
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
216
static const char* construct_prompt();
217
static char *get_arg(char *line, my_bool get_next_arg);
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
218 219
static void init_username();
static void add_int_to_prompt(int toadd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
220 221 222 223 224 225 226 227 228 229 230 231 232

/* A structure which contains information on the commands this program
   can understand. */

typedef struct {
  const char *name;		/* User printable name of the function. */
  char cmd_char;		/* msql command character */
  int (*func)(String *str,char *); /* Function to call to do the job. */
  bool takes_params;		/* Max parameters for command */
  const char *doc;		/* Documentation for this function.  */
} COMMANDS;

static COMMANDS commands[] = {
233
  { "?",      '?', com_help,   1, "Synonym for `help'." },
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
234
  { "clear",  'c', com_clear,  0, "Clear command."},
235
  { "connect",'r', com_connect,1,
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
236
    "Reconnect to the server. Optional arguments are db and host." },
237
  { "delimiter", 'd', com_delimiter,    1,
238
    "Set statement delimiter. NOTE: Takes the rest of the line as new delimiter." },
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
239
#ifdef USE_POPEN
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
240
  { "edit",   'e', com_edit,   0, "Edit command with $EDITOR."},
241
#endif
242
  { "ego",    'G', com_ego,    0,
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
243 244 245
    "Send command to mysql server, display result vertically."},
  { "exit",   'q', com_quit,   0, "Exit mysql. Same as quit."},
  { "go",     'g', com_go,     0, "Send command to mysql server." },
246
  { "help",   'h', com_help,   1, "Display this help." },
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
247
#ifdef USE_POPEN
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
248 249 250
  { "nopager",'n', com_nopager,0, "Disable pager, print to stdout." },
#endif
  { "notee",  't', com_notee,  0, "Don't write into outfile." },
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
251
#ifdef USE_POPEN
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
252 253 254 255
  { "pager",  'P', com_pager,  1, 
    "Set PAGER [to_pager]. Print the query results via PAGER." },
#endif
  { "print",  'p', com_print,  0, "Print current command." },
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
256
  { "prompt", 'R', com_prompt, 1, "Change your mysql prompt."},
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
257 258
  { "quit",   'q', com_quit,   0, "Quit mysql." },
  { "rehash", '#', com_rehash, 0, "Rebuild completion hash." },
bk@work.mysql.com's avatar
bk@work.mysql.com committed
259
  { "source", '.', com_source, 1,
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
260 261
    "Execute a SQL script file. Takes a file name as an argument."},
  { "status", 's', com_status, 0, "Get status information from the server."},
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
262
#ifdef USE_POPEN
263 264
  { "system", '!', com_shell,  1, "Execute a system shell command."},
#endif
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
265 266
  { "tee",    'T', com_tee,    1, 
    "Set outfile [to_outfile]. Append everything into given outfile." },
267
  { "use",    'u', com_use,    1,
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
268 269
    "Use another database. Takes database name as argument." },
  /* Get bash-like expansion for some commands */
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
  { "create table",     0, 0, 0, ""},
  { "create database",  0, 0, 0, ""},
  { "drop",             0, 0, 0, ""},
  { "select",           0, 0, 0, ""},
  { "insert",           0, 0, 0, ""},
  { "replace",          0, 0, 0, ""},
  { "update",           0, 0, 0, ""},
  { "delete",           0, 0, 0, ""},
  { "explain",          0, 0, 0, ""},
  { "show databases",   0, 0, 0, ""},
  { "show fields from", 0, 0, 0, ""},
  { "show keys from",   0, 0, 0, ""},
  { "show tables",      0, 0, 0, ""},
  { "load data from",   0, 0, 0, ""},
  { "alter table",      0, 0, 0, ""},
  { "set option",       0, 0, 0, ""},
  { "lock tables",      0, 0, 0, ""},
  { "unlock tables",    0, 0, 0, ""},
  { (char *)NULL,       0, 0, 0, ""}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
289 290 291
};

static const char *load_default_groups[]= { "mysql","client",0 };
292 293
static const char *server_default_groups[]=
{ "server", "embedded", "mysql_SERVER", 0 };
bk@work.mysql.com's avatar
bk@work.mysql.com committed
294 295

#ifdef HAVE_READLINE
296 297 298 299
/*
 HIST_ENTRY is defined for libedit, but not for the real readline
 Need to redefine it for real readline to find it
*/
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
300
#if !defined(HAVE_HIST_ENTRY)
301 302 303 304 305 306
typedef struct _hist_entry {
  const char      *line;
  const char      *data;
} HIST_ENTRY; 
#endif

307 308 309
extern "C" int add_history(const char *command); /* From readline directory */
extern "C" int read_history(const char *command);
extern "C" int write_history(const char *command);
310 311 312
extern "C" HIST_ENTRY *history_get(int num);
extern "C" int history_length;
static int not_in_history(const char *line);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
313
static void initialize_readline (char *name);
314
static void fix_history(String *final_command);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
315 316 317
#endif

static COMMANDS *find_command (char *name,char cmd_name);
318 319
static bool add_line(String &buffer,char *line,char *in_string,
                     bool *ml_comment);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
320 321 322
static void remove_cntrl(String &buffer);
static void print_table_data(MYSQL_RES *result);
static void print_table_data_html(MYSQL_RES *result);
323
static void print_table_data_xml(MYSQL_RES *result);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
324 325 326 327 328 329 330 331 332 333 334 335
static void print_tab_data(MYSQL_RES *result);
static void print_table_data_vertically(MYSQL_RES *result);
static ulong start_timer(void);
static void end_timer(ulong start_time,char *buff);
static void mysql_end_timer(ulong start_time,char *buff);
static void nice_time(double sec,char *buff,bool part_second);
static sig_handler mysql_end(int sig);


int main(int argc,char *argv[])
{
  char buff[80];
336 337 338 339 340 341 342 343 344 345
  char *defaults, *extra_defaults;
  char *emb_argv[3];
  int emb_argc= 1;

  emb_argv[0]= argv[0];
  get_defaults_files(argc, argv, &defaults, &extra_defaults);
  if (defaults)
    emb_argv[emb_argc++]= defaults;
  if (extra_defaults)
    emb_argv[emb_argc++]= extra_defaults;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
346 347 348 349

  MY_INIT(argv[0]);
  DBUG_ENTER("main");
  DBUG_PROCESS(argv[0]);
350 351
  
  delimiter_str= delimiter;
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
352 353 354 355 356 357
  default_prompt = my_strdup(getenv("MYSQL_PS1") ? 
			     getenv("MYSQL_PS1") : 
			     "mysql> ",MYF(MY_WME));
  current_prompt = my_strdup(default_prompt,MYF(MY_WME));
  prompt_counter=0;

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
358 359
  outfile[0]=0;			// no (default) outfile
  strmov(pager, "stdout");	// the default, if --pager wasn't given
360 361
  {
    char *tmp=getenv("PAGER");
362 363 364 365 366
    if (tmp && strlen(tmp))
    {
      default_pager_set= 1;
      strmov(default_pager, tmp);
    }
367
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
368 369 370 371 372 373 374 375 376
  if (!isatty(0) || !isatty(1))
  {
    status.batch=1; opt_silent=1;
    ignore_errors=0;
  }
  else
    status.add_to_history=1;
  status.exit_status=1;
  load_defaults("my",load_default_groups,&argc,&argv);
377
  defaults_argv=argv;
378
  if (get_options(argc, (char **) argv))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
379
  {
380
    free_defaults(defaults_argv);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
381 382 383 384
    my_end(0);
    exit(1);
  }
  if (status.batch && !status.line_buff &&
385
      !(status.line_buff=batch_readline_init(opt_max_allowed_packet+512,stdin)))
386 387
  {
    free_defaults(defaults_argv);
388
    my_end(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
389
    exit(1);
390
  }
391
  if (mysql_server_init(emb_argc, emb_argv, (char**) server_default_groups))
392 393
  {
    free_defaults(defaults_argv);
394
    my_end(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
395
    exit(1);
396
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
397
  glob_buffer.realloc(512);
398 399
  completion_hash_init(&ht, 128);
  init_alloc_root(&hash_mem_root, 16384, 0);
400
  bzero((char*) &mysql, sizeof(mysql));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
401 402 403
  if (sql_connect(current_host,current_db,current_user,opt_password,
		  opt_silent))
  {
404 405 406
    quick=1;					// Avoid history
    status.exit_status=1;
    mysql_end(-1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
407 408 409
  }
  if (!status.batch)
    ignore_errors=1;				// Don't abort monitor
410 411 412 413 414

  if (opt_sigint_ignore)
    signal(SIGINT, SIG_IGN);
  else
    signal(SIGINT, mysql_end);			// Catch SIGINT to clean up
415
  signal(SIGQUIT, mysql_end);			// Catch SIGQUIT to clean up
bk@work.mysql.com's avatar
bk@work.mysql.com committed
416

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
417
  /*
418
    Run in interactive mode like the ingres/postgres monitor
bk@work.mysql.com's avatar
bk@work.mysql.com committed
419 420 421 422 423
  */

  put_info("Welcome to the MySQL monitor.  Commands end with ; or \\g.",
	   INFO_INFO);
  sprintf((char*) glob_buffer.ptr(),
424
	  "Your MySQL connection id is %lu to server version: %s\n",
bk@work.mysql.com's avatar
bk@work.mysql.com committed
425 426 427 428 429
	  mysql_thread_id(&mysql),mysql_get_server_info(&mysql));
  put_info((char*) glob_buffer.ptr(),INFO_INFO);

#ifdef HAVE_READLINE
  initialize_readline(my_progname);
430
  if (!status.batch && !quick && !opt_html && !opt_xml)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
431
  {
432
    /* read-history from file, default ~/.mysql_history*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
433 434 435 436
    if (getenv("MYSQL_HISTFILE"))
      histfile=my_strdup(getenv("MYSQL_HISTFILE"),MYF(MY_WME));
    else if (getenv("HOME"))
    {
437 438
      histfile=(char*) my_malloc((uint) strlen(getenv("HOME"))
				 + (uint) strlen("/.mysql_history")+2,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
439 440 441 442 443 444 445
				 MYF(MY_WME));
      if (histfile)
	sprintf(histfile,"%s/.mysql_history",getenv("HOME"));
    }
    if (histfile)
    {
      if (verbose)
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
446
	tee_fprintf(stdout, "Reading history-file %s\n",histfile);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
447
      read_history(histfile);
448 449 450 451 452 453 454
      if (!(histfile_tmp= (char*) my_malloc((uint) strlen(histfile) + 5,
					    MYF(MY_WME))))
      {
	fprintf(stderr, "Couldn't allocate memory for temp histfile!\n");
	exit(1);
      }
      sprintf(histfile_tmp, "%s.TMP", histfile);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
455 456 457
    }
  }
#endif
458
  sprintf(buff, "%s",
459
#ifndef NOT_YET
460
	  "Type 'help;' or '\\h' for help. Type '\\c' to clear the buffer.\n");
461
#else
462
	  "Type 'help [[%]function name[%]]' to get help on usage of function.\n");
463
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
464 465
  put_info(buff,INFO_INFO);
  status.exit_status=read_lines(1);		// read lines and execute them
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
466 467
  if (opt_outfile)
    end_tee();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
468 469 470 471 472 473 474 475
  mysql_end(0);
#ifndef _lint
  DBUG_RETURN(0);				// Keep compiler happy
#endif
}

sig_handler mysql_end(int sig)
{
476
  mysql_close(&mysql);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
477
#ifdef HAVE_READLINE
478
  if (!status.batch && !quick && !opt_html && !opt_xml)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
479 480 481
  {
    /* write-history */
    if (verbose)
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
482
      tee_fprintf(stdout, "Writing history-file %s\n",histfile);
483 484
    if (!write_history(histfile_tmp))
      my_rename(histfile_tmp, histfile, MYF(MY_WME));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
485 486 487
  }
  batch_readline_end(status.line_buff);
  completion_hash_free(&ht);
488 489
  free_root(&hash_mem_root,MYF(0));

bk@work.mysql.com's avatar
bk@work.mysql.com committed
490
#endif
491 492
  if (sig >= 0)
    put_info(sig ? "Aborted" : "Bye", INFO_RESULT);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
493 494
  glob_buffer.free();
  old_buffer.free();
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
495
  processed_prompt.free();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
496 497 498
  my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
  my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR));
  my_free(histfile,MYF(MY_ALLOW_ZERO_PTR));
499
  my_free(histfile_tmp,MYF(MY_ALLOW_ZERO_PTR));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
500 501 502
  my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
  my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
  my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
503 504 505
  my_free(full_username,MYF(MY_ALLOW_ZERO_PTR));
  my_free(part_username,MYF(MY_ALLOW_ZERO_PTR));
  my_free(default_prompt,MYF(MY_ALLOW_ZERO_PTR));
506 507 508
#ifdef HAVE_SMEM
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
#endif
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
509
  my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR));
510
  mysql_server_end();
511
  free_defaults(defaults_argv);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
512 513 514 515
  my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
  exit(status.exit_status);
}

516 517

static struct my_option my_long_options[] =
bk@work.mysql.com's avatar
bk@work.mysql.com committed
518
{
519 520
  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
   0, 0, 0, 0, 0},
521 522
  {"help", 'I', "Synonym for -?", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
   0, 0, 0, 0, 0},
523 524
  {"auto-rehash", OPT_AUTO_REHASH,
   "Enable automatic rehashing. One doesn't need to use 'rehash' to get table and field completion, but startup and reconnecting may take a longer time. Disable with --disable-auto-rehash.",
525
   (gptr*) &rehash, (gptr*) &rehash, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
526
  {"no-auto-rehash", 'A',
527
   "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.",
528 529
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"batch", 'B',
serg@serg.mylan's avatar
serg@serg.mylan committed
530
   "Don't use history file. Disable interactive behavior. (Enables --silent)", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
531 532 533
  {"character-sets-dir", OPT_CHARSETS_DIR,
   "Directory where character sets are.", (gptr*) &charsets_dir,
   (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
534 535 536
  {"default-character-set", OPT_DEFAULT_CHARSET,
   "Set the default character set.", (gptr*) &default_charset,
   (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
537 538 539
  {"compress", 'C', "Use compression in server/client protocol.",
   (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
   0, 0, 0},
540 541
#ifdef DBUG_OFF
  {"debug", '#', "This is a non-debug version. Catch this and exit",
serg@serg.mylan's avatar
serg@serg.mylan committed
542
   0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
543 544
#else
  {"debug", '#', "Output debug log", (gptr*) &default_dbug_option,
545 546
   (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
547
  {"database", 'D', "Database to use.", (gptr*) &current_db,
548
   (gptr*) &current_db, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
549 550
  {"delimiter", OPT_DELIMITER, "Delimiter to be used.", (gptr*) &delimiter_str,
   (gptr*) &delimiter_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
serg@serg.mylan's avatar
serg@serg.mylan committed
551
  {"execute", 'e', "Execute command and quit. (Disables --force and history file)", 0,
552 553 554 555 556 557 558
   0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  {"vertical", 'E', "Print the output of a query (rows) vertically.",
   (gptr*) &vertical, (gptr*) &vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
   0},
  {"force", 'f', "Continue even if we get an sql error.",
   (gptr*) &ignore_errors, (gptr*) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
   0, 0, 0, 0},
559
  {"no-named-commands", 'g',
560
   "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.",
561 562
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"named-commands", 'G',
563
   "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.",
564 565
   (gptr*) &named_cmds, (gptr*) &named_cmds, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
   0, 0},
566
  {"ignore-spaces", 'i', "Ignore space after function names.", 0, 0, 0,
567
   GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
568
  {"local-infile", OPT_LOCAL_INFILE, "Enable/disable LOAD DATA LOCAL INFILE.",
569 570
   (gptr*) &opt_local_infile,
   (gptr*) &opt_local_infile, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
571 572
  {"no-beep", 'b', "Turn off beep on error.", (gptr*) &opt_nobeep,
   (gptr*) &opt_nobeep, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 
573
  {"host", 'h', "Connect to host.", (gptr*) &current_host,
574
   (gptr*) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
575 576 577 578 579 580
  {"html", 'H', "Produce HTML output.", (gptr*) &opt_html, (gptr*) &opt_html,
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"xml", 'X', "Produce XML output", (gptr*) &opt_xml, (gptr*) &opt_xml, 0,
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"line-numbers", OPT_LINE_NUMBERS, "Write line numbers for errors.",
   (gptr*) &line_numbers, (gptr*) &line_numbers, 0, GET_BOOL,
581
   NO_ARG, 1, 0, 0, 0, 0, 0},  
582
  {"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,
583
   NO_ARG, 0, 0, 0, 0, 0, 0},
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
584
#ifdef USE_POPEN
585
  {"no-pager", OPT_NOPAGER,
586
   "Disable pager and print to stdout. See interactive help (\\h) also. WARNING: option deprecated; use --disable-pager instead.",
587
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
588
#endif
589
  {"no-tee", OPT_NOTEE, "Disable outfile. See interactive help (\\h) also. WARNING: option deprecated; use --disable-tee instead", 0, 0, 0, GET_NO_ARG,
590 591 592 593 594
   NO_ARG, 0, 0, 0, 0, 0, 0},
  {"unbuffered", 'n', "Flush buffer after each query.", (gptr*) &unbuffered,
   (gptr*) &unbuffered, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"column-names", OPT_COLUMN_NAMES, "Write column names in results.",
   (gptr*) &column_names, (gptr*) &column_names, 0, GET_BOOL,
595
   NO_ARG, 1, 0, 0, 0, 0, 0},
596
  {"skip-column-names", 'N',
597
   "Don't write column names in results. WARNING: -N is deprecated, use long version of this options instead.",
598 599
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"set-variable", 'O',
600
   "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
601
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
602 603 604
  {"sigint-ignore", OPT_SIGINT_IGNORE, "Ignore SIGINT (CTRL-C)",
   (gptr*) &opt_sigint_ignore,  (gptr*) &opt_sigint_ignore, 0, GET_BOOL,
   NO_ARG, 0, 0, 0, 0, 0, 0},
605 606 607
  {"one-database", 'o',
   "Only update the default database. This is useful for skipping updates to other database in the update log.",
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
608
#ifdef USE_POPEN
609 610 611
  {"pager", OPT_PAGER,
   "Pager to use to display results. If you don't supply an option the default pager is taken from your ENV variable PAGER. Valid pagers are less, more, cat [> filename], etc. See interactive help (\\h) also. This option does not work in batch mode.",
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
612
#endif
613 614 615
  {"password", 'p',
   "Password to use when connecting to server. If password is not given it's asked from the tty.",
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
616
#ifdef __WIN__
617 618
  {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
619
#endif
620 621 622
  {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
   (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
   0},
623
  {"prompt", OPT_PROMPT, "Set the mysql prompt to this value.",
624
   (gptr*) &current_prompt, (gptr*) &current_prompt, 0, GET_STR_ALLOC,
625
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
626
  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
627
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
628
  {"quick", 'q',
629
   "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.",
630
   (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
631
  {"raw", 'r', "Write fields without conversion. Used with --batch.",
632 633
   (gptr*) &opt_raw_data, (gptr*) &opt_raw_data, 0, GET_BOOL, NO_ARG, 0, 0, 0,
   0, 0, 0},
634 635
  {"reconnect", OPT_RECONNECT, "Reconnect if the connection is lost. Disable with --disable-reconnect. This option is enabled by default.", 
   (gptr*) &opt_reconnect, (gptr*) &opt_reconnect, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
serg@serg.mylan's avatar
serg@serg.mylan committed
636
  {"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,
637
   0, 0},
638
#ifdef HAVE_SMEM
639
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
640
   "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name, 
641 642
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
643
  {"socket", 'S', "Socket file to use for connection.",
644
   (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR_ALLOC,
645
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
646
#include "sslopt-longopts.h"
647 648 649 650 651 652 653
  {"table", 't', "Output in table format.", (gptr*) &output_tables,
   (gptr*) &output_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"debug-info", 'T', "Print some debug info at exit.", (gptr*) &info_flag,
   (gptr*) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"tee", OPT_TEE,
   "Append everything into outfile. See interactive help (\\h) also. Does not work in batch mode.",
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
654
#ifndef DONT_ALLOW_USER_CHANGE
655
  {"user", 'u', "User for login if not current user.", (gptr*) &current_user,
656
   (gptr*) &current_user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
657
#endif
658
  {"safe-updates", 'U', "Only allow UPDATE and DELETE that uses keys.",
659
   (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0,
660
   0, 0, 0, 0},
661
  {"i-am-a-dummy", 'U', "Synonym for option --safe-updates, -U.",
662
   (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0,
663
   0, 0, 0, 0},
664
  {"verbose", 'v', "Write more. (-v -v -v gives the table output format).", 0,
665 666 667 668 669
   0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"version", 'V', "Output version information and exit.", 0, 0, 0,
   GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"wait", 'w', "Wait and retry if connection is down.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
670 671 672
  {"connect_timeout", OPT_CONNECT_TIMEOUT,
   "Number of seconds before connection timeout.",
   (gptr*) &opt_connect_timeout,
673
   (gptr*) &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3600*12, 0,
674
   0, 1},
675 676
  {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET,
   "Max packet length to send to, or receive from server",
677
   (gptr*) &opt_max_allowed_packet, (gptr*) &opt_max_allowed_packet, 0, GET_ULONG,
678 679
   REQUIRED_ARG, 16 *1024L*1024L, 4096, (longlong) 2*1024L*1024L*1024L,
   MALLOC_OVERHEAD, 1024, 0},
680 681
  {"net_buffer_length", OPT_NET_BUFFER_LENGTH,
   "Buffer for TCP/IP and socket communication",
682
   (gptr*) &opt_net_buffer_length, (gptr*) &opt_net_buffer_length, 0, GET_ULONG,
683
   REQUIRED_ARG, 16384, 1024, 512*1024*1024L, MALLOC_OVERHEAD, 1024, 0},
684 685 686
  {"select_limit", OPT_SELECT_LIMIT,
   "Automatic limit for SELECT when using --safe-updates",
   (gptr*) &select_limit,
687
   (gptr*) &select_limit, 0, GET_ULONG, REQUIRED_ARG, 1000L, 1, ~0L, 0, 1, 0},
688 689 690
  {"max_join_size", OPT_MAX_JOIN_SIZE,
   "Automatic limit for rows in a join when using --safe-updates",
   (gptr*) &max_join_size,
691
   (gptr*) &max_join_size, 0, GET_ULONG, REQUIRED_ARG, 1000000L, 1, ~0L, 0, 1,
692
   0},
693 694 695
  {"secure-auth", OPT_SECURE_AUTH, "Refuse client connecting to server if it"
    " uses old (pre-4.1.1) protocol", (gptr*) &opt_secure_auth,
    (gptr*) &opt_secure_auth, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
696
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
697 698 699 700 701
};


static void usage(int version)
{
monty@mysql.com's avatar
monty@mysql.com committed
702 703 704 705
  /* Divert all help information on NetWare to logger screen. */
#ifdef __NETWARE__
#define printf	consoleprintf
#endif
706 707 708 709 710 711 712

#if defined(USE_LIBEDIT_INTERFACE)
  const char* readline= "";
#else
  const char* readline= "readline";
#endif

713
#ifdef HAVE_READLINE
714 715 716
  printf("%s  Ver %s Distrib %s, for %s (%s) using %s %s\n",
	 my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE,
         readline, rl_library_version);
717 718 719 720 721
#else
  printf("%s  Ver %s Distrib %s, for %s (%s)", my_progname, VER,
	MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
#endif

bk@work.mysql.com's avatar
bk@work.mysql.com committed
722 723
  if (version)
    return;
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
724
  printf("\
725
Copyright (C) 2002 MySQL AB\n\
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
726 727
This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
and you are welcome to modify and redistribute it under the GPL license\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
728
  printf("Usage: %s [OPTIONS] [database]\n", my_progname);
729
  my_print_help(my_long_options);
730
  print_defaults("my", load_default_groups);
731
  my_print_variables(my_long_options);
monty@mysql.com's avatar
monty@mysql.com committed
732 733 734 735
  NETWARE_SET_SCREEN_MODE(1);
#ifdef __NETWARE__
#undef printf
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
736 737
}

monty@mysql.com's avatar
monty@mysql.com committed
738

739 740 741
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
	       char *argument)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
742
{
743
  switch(optid) {
744 745 746 747
  case OPT_CHARSETS_DIR:
    strmov(mysql_charsets_dir, argument);
    charsets_dir = mysql_charsets_dir;
    break;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
748 749 750
  case  OPT_DEFAULT_CHARSET:
    default_charset_used= 1;
    break;
751 752 753 754 755
  case OPT_DELIMITER:
    if (argument == disabled_my_option)
      strmov(delimiter, DEFAULT_DELIMITER);
    else
      strmake(delimiter, argument, sizeof(delimiter) - 1);
756
    delimiter_length= (uint)strlen(delimiter);
757 758
    delimiter_str= delimiter;
    break;
759 760 761 762 763 764
  case OPT_LOCAL_INFILE:
    using_opt_local_infile=1;
    break;
  case OPT_TEE:
    if (argument == disabled_my_option)
    {
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
765 766
      if (opt_outfile)
	end_tee();
767 768
    }
    else
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
769
      init_tee(argument);
770 771
    break;
  case OPT_NOTEE:
772
    printf("WARNING: option deprecated; use --disable-tee instead.\n");
773 774 775 776
    if (opt_outfile)
      end_tee();
    break;
  case OPT_PAGER:
777 778
    if (argument == disabled_my_option)
      opt_nopager= 1;
779
    else
780 781
    {
      opt_nopager= 0;
782 783 784
      if (argument && strlen(argument))
      {
	default_pager_set= 1;
785
	strmov(pager, argument);
786 787 788
	strmov(default_pager, pager);
      }
      else if (default_pager_set)
789
	strmov(pager, default_pager);
790 791
      else
	opt_nopager= 1;
792
    }
793 794
    break;
  case OPT_NOPAGER:
795
    printf("WARNING: option deprecated; use --disable-pager instead.\n");
796
    opt_nopager= 1;
797 798
  case OPT_MYSQL_PROTOCOL:
  {
799
    if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0)
800 801 802 803 804 805
    {
      fprintf(stderr, "Unknown option to protocol: %s\n", argument);
      exit(1);
    }
    break;
  }
806
  break;
807 808 809 810 811 812 813 814 815
  case 'A':
    rehash= 0;
    break;
  case 'N':
    column_names= 0;
    break;
  case 'e':
    status.batch= 1;
    status.add_to_history= 0;
serg@serg.mylan's avatar
serg@serg.mylan committed
816 817 818
    if (!status.line_buff)
      ignore_errors= 0;                         // do it for the first -e only
    if (!(status.line_buff= batch_readline_command(status.line_buff, argument)))
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
      return 1;
    break;
  case 'o':
    if (argument == disabled_my_option)
      one_database= 0;
    else
      one_database= skip_updates= 1;
    break;
  case 'p':
    if (argument == disabled_my_option)
      argument= (char*) "";			// Don't require password
    if (argument)
    {
      char *start= argument;
      my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
      opt_password= my_strdup(argument, MYF(MY_FAE));
      while (*argument) *argument++= 'x';		// Destroy argument
      if (*start)
	start[1]=0 ;
838
      tty_password= 0;
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
    }
    else
      tty_password= 1;
    break;
  case '#':
    DBUG_PUSH(argument ? argument : default_dbug_option);
    info_flag= 1;
    break;
  case 's':
    if (argument == disabled_my_option)
      opt_silent= 0;
    else
      opt_silent++;
    break;
  case 'v':
    if (argument == disabled_my_option)
      verbose= 0;
    else
      verbose++;
    break;
  case 'B':
serg@serg.mylan's avatar
serg@serg.mylan committed
860 861
    status.batch= 1;
    status.add_to_history= 0;
862
    set_if_bigger(opt_silent,1);                         // more silent
863 864
    break;
  case 'W':
bk@work.mysql.com's avatar
bk@work.mysql.com committed
865
#ifdef __WIN__
866
    opt_protocol = MYSQL_PROTOCOL_PIPE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
867
#endif
868
    break;
869
#include <sslopt-case.h>
870 871 872 873 874 875 876
  case 'V':
    usage(1);
    exit(0);
  case 'I':
  case '?':
    usage(0);
    exit(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
877
  }
878 879 880 881 882 883 884 885
  return 0;
}


static int get_options(int argc, char **argv)
{
  char *tmp, *pagpoint;
  int ho_error;
886
  MYSQL_PARAMETERS *mysql_params= mysql_get_parameters();
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901

  tmp= (char *) getenv("MYSQL_HOST");
  if (tmp)
    current_host= my_strdup(tmp, MYF(MY_WME));

  pagpoint= getenv("PAGER");
  if (!((char*) (pagpoint)))
  {
    strmov(pager, "stdout");
    opt_nopager= 1;
  }
  else
    strmov(pager, pagpoint);
  strmov(default_pager, pager);

902 903 904
  opt_max_allowed_packet= *mysql_params->p_max_allowed_packet;
  opt_net_buffer_length= *mysql_params->p_net_buffer_length;

905
  if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
906
    exit(ho_error);
907

908 909 910
  *mysql_params->p_max_allowed_packet= opt_max_allowed_packet;
  *mysql_params->p_net_buffer_length= opt_net_buffer_length;

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
911 912 913 914
  if (status.batch) /* disable pager and outfile in this case */
  {
    strmov(default_pager, "stdout");
    strmov(pager, "stdout");
915
    opt_nopager= 1;
916
    default_pager_set= 0;
917
    opt_outfile= 0;
918
    opt_reconnect= 0;
919
    connect_flag= 0; /* Not in interactive mode */
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
920
  }
921 922 923
  
  if (strcmp(default_charset, charset_info->csname) &&
      !(charset_info= get_charset_by_csname(default_charset, 
924
					    MY_CS_PRIMARY, MYF(MY_WME))))
925
    exit(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
926 927 928 929 930 931 932
  if (argc > 1)
  {
    usage(0);
    exit(1);
  }
  if (argc == 1)
  {
933
    skip_updates= 0;
934 935
    my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
    current_db= my_strdup(*argv, MYF(MY_WME));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
936 937
  }
  if (tty_password)
938
    opt_password= get_tty_password(NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
939 940 941 942 943
  return(0);
}

static int read_lines(bool execute_commands)
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
944
#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
945 946 947 948 949
  char linebuffer[254];
#endif
  char	*line;
  char	in_string=0;
  ulong line_number=0;
950
  bool ml_comment= 0;  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
951 952
  COMMANDS *com;
  status.exit_status=1;
953
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
954 955 956 957 958 959 960 961 962 963
  for (;;)
  {
    if (status.batch || !execute_commands)
    {
      line=batch_readline(status.line_buff);
      line_number++;
      if (!glob_buffer.length())
	status.query_start_line=line_number;
    }
    else
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
964
    {
965 966
      char *prompt= (char*) (ml_comment ? "   /*> " :
                             glob_buffer.is_empty() ?  construct_prompt() :
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
967 968
			     !in_string ? "    -> " :
			     in_string == '\'' ?
969 970 971
			     "    '> " : (in_string == '`' ?
			     "    `> " :
			     "    \"> "));
972 973
      if (opt_outfile && glob_buffer.is_empty())
	fflush(OUTFILE);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
974 975 976 977 978 979

#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
      tee_fputs(prompt, stdout);
#ifdef __NETWARE__
      line=fgets(linebuffer, sizeof(linebuffer)-1, stdin);
      /* Remove the '\n' */
monty@mysql.com's avatar
monty@mysql.com committed
980
      if (line)
981
      {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
982
        char *p = strrchr(line, '\n');
983 984
        if (p != NULL)
          *p = '\0';
985
      }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
986 987 988 989 990 991 992 993 994 995
#else
      linebuffer[0]= (char) sizeof(linebuffer);
      line= _cgets(linebuffer);
#endif /* __NETWARE__ */
#else
      if (opt_outfile)
	fputs(prompt, OUTFILE);
      line= readline(prompt);
#endif /* defined( __WIN__) || defined(OS2) || defined(__NETWARE__) */

monty@mysql.com's avatar
monty@mysql.com committed
996 997 998 999 1000
      /*
        When Ctrl+d or Ctrl+z is pressed, the line may be NULL on some OS
        which may cause coredump.
      */
      if (opt_outfile && line)
1001
	fprintf(OUTFILE, "%s\n", line);
1002
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1003 1004 1005 1006 1007 1008 1009 1010
    if (!line)					// End of file
    {
      status.exit_status=0;
      break;
    }
    if (!in_string && (line[0] == '#' ||
		       (line[0] == '-' && line[1] == '-') ||
		       line[0] == 0))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1011
      continue;					// Skip comment lines
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1012

1013 1014 1015 1016
    /*
      Check if line is a mysql command line
      (We want to allow help, print and clear anywhere at line start
    */
1017
    if (execute_commands && (named_cmds || glob_buffer.is_empty()) 
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1018
	&& !in_string && (com=find_command(line,0)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1019 1020 1021 1022 1023 1024
    {
      if ((*com->func)(&glob_buffer,line) > 0)
	break;
      if (glob_buffer.is_empty())		// If buffer was emptied
	in_string=0;
#ifdef HAVE_READLINE
1025
      if (status.add_to_history && not_in_history(line))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1026 1027 1028 1029
	add_history(line);
#endif
      continue;
    }
1030
    if (add_line(glob_buffer,line,&in_string,&ml_comment))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
      break;
  }
  /* if in batch mode, send last query even if it doesn't end with \g or go */

  if ((status.batch || !execute_commands) && !status.exit_status)
  {
    remove_cntrl(glob_buffer);
    if (!glob_buffer.is_empty())
    {
      status.exit_status=1;
      if (com_go(&glob_buffer,line) <= 0)
	status.exit_status=0;
    }
  }
  return status.exit_status;
}


static COMMANDS *find_command (char *name,char cmd_char)
{
  uint len;
  char *end;

  if (!name)
  {
    len=0;
    end=0;
  }
  else
  {
1061
    while (my_isspace(charset_info,*name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1062
      name++;
1063 1064 1065 1066 1067 1068
    /*
      As special case we allow row that starts with word delimiter
      to be able to change delimiter if someone has delimiter 'delimiter'.
    */
    if (strstr(name, "\\g") || (strstr(name, delimiter) &&
				strncmp(name, "delimiter", 9)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1069 1070 1071 1072
      return ((COMMANDS *) 0);
    if ((end=strcont(name," \t")))
    {
      len=(uint) (end - name);
1073
      while (my_isspace(charset_info,*end))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1074 1075 1076 1077 1078
	end++;
      if (!*end)
	end=0;					// no arguments to function
    }
    else
1079
      len=(uint) strlen(name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1080 1081 1082 1083 1084
  }

  for (uint i= 0; commands[i].name; i++)
  {
    if (commands[i].func &&
1085
	((name && 
1086 1087
	  !my_strnncoll(charset_info,(uchar*)name,len,
				     (uchar*)commands[i].name,len) &&
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1088 1089 1090 1091 1092 1093 1094 1095 1096
	  !commands[i].name[len] &&
	  (!end || (end && commands[i].takes_params))) ||
	 !name && commands[i].cmd_char == cmd_char))
      return (&commands[i]);
  }
  return ((COMMANDS *) 0);
}


1097 1098
static bool add_line(String &buffer,char *line,char *in_string,
                     bool *ml_comment)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1099 1100
{
  uchar inchar;
1101
  char buff[80], *pos, *out;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1102
  COMMANDS *com;
antony@ltantony.mysql.com's avatar
antony@ltantony.mysql.com committed
1103
  bool need_space= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1104 1105 1106 1107

  if (!line[0] && buffer.is_empty())
    return 0;
#ifdef HAVE_READLINE
1108
  if (status.add_to_history && line[0] && not_in_history(line))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1109 1110 1111
    add_history(line);
#endif
#ifdef USE_MB
1112
  char *strend=line+(uint) strlen(line);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1113 1114 1115 1116
#endif

  for (pos=out=line ; (inchar= (uchar) *pos) ; pos++)
  {
1117
    if (my_isspace(charset_info,inchar) && out == line && 
1118
        buffer.is_empty())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1119 1120 1121
      continue;
#ifdef USE_MB
    int l;
1122 1123
    if (use_mb(charset_info) &&
        (l = my_ismbchar(charset_info, pos, strend))) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1124 1125 1126 1127 1128 1129
	while (l--)
	    *out++ = *pos++;
	pos--;
	continue;
    }
#endif
1130
    if (!*ml_comment && inchar == '\\')
1131 1132 1133
    {
      // Found possbile one character command like \c

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1134 1135
      if (!(inchar = (uchar) *++pos))
	break;				// readline adds one '\'
1136
      if (*in_string || inchar == 'N')	// \N is short for NULL
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1137 1138 1139 1140 1141 1142 1143
      {					// Don't allow commands in string
	*out++='\\';
	*out++= (char) inchar;
	continue;
      }
      if ((com=find_command(NullS,(char) inchar)))
      {
1144
	const String tmp(line,(uint) (out-line), charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1145 1146 1147 1148 1149
	buffer.append(tmp);
	if ((*com->func)(&buffer,pos-1) > 0)
	  return 1;				// Quit
	if (com->takes_params)
	{
1150 1151 1152 1153
	  for (pos++ ;
	       *pos && (*pos != *delimiter ||
			!is_prefix(pos + 1, delimiter + 1)) ; pos++)
	    ;	// Remove parameters
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1154 1155
	  if (!*pos)
	    pos--;
1156 1157
	  else 
	    pos+= delimiter_length - 1; // Point at last delim char
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
	}
	out=line;
      }
      else
      {
	sprintf(buff,"Unknown command '\\%c'.",inchar);
	if (put_info(buff,INFO_ERROR) > 0)
	  return 1;
	*out++='\\';
	*out++=(char) inchar;
	continue;
      }
    }
1171 1172 1173 1174 1175 1176

    else if (!*ml_comment && (*pos == *delimiter &&
			      is_prefix(pos + 1, delimiter + 1)) &&
	     !*in_string)
    {					
      uint old_delimiter_length= delimiter_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1177
      if (out != line)
1178 1179
	buffer.append(line, (uint) (out - line));	// Add this line
      if ((com= find_command(buffer.c_ptr(), 0)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1180
      {
1181
	if ((*com->func)(&buffer, buffer.c_ptr()) > 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1182 1183 1184 1185
	  return 1;				// Quit
      }
      else
      {
serg@serg.mylan's avatar
serg@serg.mylan committed
1186 1187
	if (com_go(&buffer, 0) > 0)             // < 0 is not fatal
	  return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1188 1189
      }
      buffer.length(0);
1190 1191
      out= line;
      pos+= old_delimiter_length - 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1192
    }
1193 1194
    else if (!*ml_comment && (!*in_string && (inchar == '#' ||
			      inchar == '-' && pos[1] == '-' &&
1195
			      my_isspace(charset_info,pos[2]))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1196
      break;					// comment to end of line
1197 1198
    else if (!*in_string && inchar == '/' && *(pos+1) == '*' &&
	     *(pos+2) != '!')
1199 1200 1201 1202 1203 1204 1205 1206 1207
    {
      pos++;
      *ml_comment= 1;
      if (out != line)
      {
        buffer.append(line,(uint) (out-line));
        out=line;
      }
    }
1208
    else if (*ml_comment && inchar == '*' && *(pos + 1) == '/')
1209 1210 1211
    {
      pos++;
      *ml_comment= 0;
antony@ltantony.mysql.com's avatar
antony@ltantony.mysql.com committed
1212
      need_space= 1;
1213
    }      
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1214 1215 1216
    else
    {						// Add found char to buffer
      if (inchar == *in_string)
1217
	*in_string= 0;
1218 1219 1220 1221
      else if (!*ml_comment && !*in_string &&
	       (inchar == '\'' || inchar == '"' || inchar == '`'))
	*in_string= (char) inchar;
      if (!*ml_comment)
antony@ltantony.mysql.com's avatar
antony@ltantony.mysql.com committed
1222 1223 1224 1225 1226 1227
      {
        if (need_space && !my_isspace(charset_info, (char)inchar))
        {
          *out++= ' ';
          need_space= 0;
        }
1228
	*out++= (char) inchar;
antony@ltantony.mysql.com's avatar
antony@ltantony.mysql.com committed
1229
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1230 1231 1232 1233 1234 1235 1236 1237
    }
  }
  if (out != line || !buffer.is_empty())
  {
    *out++='\n';
    uint length=(uint) (out-line);
    if (buffer.length() + length >= buffer.alloced_length())
      buffer.realloc(buffer.length()+length+IO_SIZE);
1238
    if (!(*ml_comment) && buffer.append(line,length))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1239 1240 1241 1242 1243
      return 1;
  }
  return 0;
}

1244 1245 1246
/*****************************************************************
	    Interface to Readline Completion
******************************************************************/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1247 1248 1249

#ifdef HAVE_READLINE

1250 1251
static char *new_command_generator(const char *text, int);
static char **new_mysql_completion (const char *text, int start, int end);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1252

1253 1254 1255 1256 1257
/*
  Tell the GNU Readline library how to complete.  We want to try to complete
  on command names if this is the first word in the line, or on filenames
  if not.
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1258

1259 1260 1261 1262 1263
#if defined(USE_NEW_READLINE_INTERFACE) || defined(USE_LIBEDIT_INTERFACE)
char *no_completion(const char*,int)
#else
int no_completion()
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1264 1265 1266 1267
{
  return 0;					/* No filename completion */
}

1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335
/*	glues pieces of history back together if in pieces   */
static void fix_history(String *final_command) 
{
  int total_lines = 1;
  char *ptr = final_command->c_ptr();
  String fixed_buffer; 	/* Converted buffer */
  char str_char = '\0';  /* Character if we are in a string or not */
  
  /* find out how many lines we have and remove newlines */
  while (*ptr != '\0') 
  {
    switch (*ptr) {
      /* string character */
    case '"':
    case '\'':
    case '`':
      if (str_char == '\0')	/* open string */
	str_char = *ptr;
      else if (str_char == *ptr)   /* close string */
	str_char = '\0';
      fixed_buffer.append(ptr,1);
      break;
    case '\n':
      /* 
	 not in string, change to space
	 if in string, leave it alone 
      */
      fixed_buffer.append(str_char == '\0' ? " " : "\n");
      total_lines++;
      break;
    case '\\':
      fixed_buffer.append('\\');
      /* need to see if the backslash is escaping anything */
      if (str_char) 
      {
	ptr++;
	/* special characters that need escaping */
	if (*ptr == '\'' || *ptr == '"' || *ptr == '\\')
	  fixed_buffer.append(ptr,1);
	else
	  ptr--;
      }
      break;
      
    default:
      fixed_buffer.append(ptr,1);
    }
    ptr++;
  }
  if (total_lines > 1)			
    add_history(fixed_buffer.ptr());
}

/*	
  returns 0 if line matches the previous history entry
  returns 1 if the line doesn't match the previous history entry
*/
static int not_in_history(const char *line) 
{
  HIST_ENTRY *oldhist = history_get(history_length);
  
  if (oldhist == 0)
    return 1;
  if (strcmp(oldhist->line,line) == 0)
    return 0;
  return 1;
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1336 1337 1338 1339 1340 1341
static void initialize_readline (char *name)
{
  /* Allow conditional parsing of the ~/.inputrc file. */
  rl_readline_name = name;

  /* Tell the completer that we want a crack first. */
1342 1343 1344 1345
#if defined(USE_NEW_READLINE_INTERFACE)
  rl_attempted_completion_function= (rl_completion_func_t*)&new_mysql_completion;
  rl_completion_entry_function= (rl_compentry_func_t*)&no_completion;
#elif defined(USE_LIBEDIT_INTERFACE)
1346 1347 1348
#ifdef HAVE_LOCALE_H
  setlocale(LC_ALL,""); /* so as libedit use isprint */
#endif
1349
  rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion;
1350
  rl_completion_entry_function= (Function*)&no_completion;
1351
#else
1352 1353
  rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion;
  rl_completion_entry_function= (Function*)&no_completion;
1354
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1355 1356
}

1357 1358 1359 1360 1361 1362
/*
  Attempt to complete on the contents of TEXT.  START and END show the
  region of TEXT that contains the word to complete.  We can use the
  entire line in case we want to do some simple parsing.  Return the
  array of matches, or NULL if there aren't any.
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1363

1364
static char **new_mysql_completion (const char *text,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1365 1366 1367 1368
				    int start __attribute__((unused)),
				    int end __attribute__((unused)))
{
  if (!status.batch && !quick)
1369
#if defined(USE_NEW_READLINE_INTERFACE)
1370
    return rl_completion_matches(text, new_command_generator);
1371 1372 1373
#else
    return completion_matches((char *)text, (CPFunction *)new_command_generator);
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1374 1375 1376 1377
  else
    return (char**) 0;
}

1378
static char *new_command_generator(const char *text,int state)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1379 1380 1381 1382 1383 1384 1385
{
  static int textlen;
  char *ptr;
  static Bucket *b;
  static entry *e;
  static uint i;

1386
  if (!state)
1387
    textlen=(uint) strlen(text);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1388

1389 1390 1391 1392
  if (textlen>0)
  {						/* lookup in the hash */
    if (!state)
    {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1393 1394
      uint len;

1395
      b = find_all_matches(&ht,text,(uint) strlen(text),&len);
1396
      if (!b)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1397 1398 1399 1400
	return NullS;
      e = b->pData;
    }

1401 1402
    if (e)
    {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1403 1404 1405 1406
      ptr= strdup(e->str);
      e = e->pNext;
      return ptr;
    }
1407 1408 1409
  }
  else
  { /* traverse the entire hash, ugly but works */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1410

1411 1412
    if (!state)
    {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1413
      /* find the first used bucket */
1414 1415 1416 1417
      for (i=0 ; i < ht.nTableSize ; i++)
      {
	if (ht.arBuckets[i])
	{
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1418 1419 1420 1421 1422 1423 1424
	  b = ht.arBuckets[i];
	  e = b->pData;
	  break;
	}
      }
    }
    ptr= NullS;
1425 1426 1427
    while (e && !ptr)
    {					/* find valid entry in bucket */
      if ((uint) strlen(e->str) == b->nKeyLength)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1428 1429 1430
	ptr = strdup(e->str);
      /* find the next used entry */
      e = e->pNext;
1431 1432
      if (!e)
      { /* find the next used bucket */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1433
	b = b->pNext;
1434 1435 1436 1437 1438 1439
	if (!b)
	{
	  for (i++ ; i<ht.nTableSize; i++)
	  {
	    if (ht.arBuckets[i])
	    {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1440 1441 1442 1443 1444 1445
	      b = ht.arBuckets[i];
	      e = b->pData;
	      break;
	    }
	  }
	}
1446 1447
	else
	  e = b->pData;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1448 1449
      }
    }
1450
    if (ptr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1451 1452 1453 1454 1455 1456 1457 1458
      return ptr;
  }
  return NullS;
}


/* Build up the completion hash */

1459
static void build_completion_hash(bool rehash, bool write_info)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1460 1461
{
  COMMANDS *cmd=commands;
1462 1463
  MYSQL_RES *databases=0,*tables=0;
  MYSQL_RES *fields;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1464 1465 1466 1467 1468 1469 1470
  static char ***field_names= 0;
  MYSQL_ROW database_row,table_row;
  MYSQL_FIELD *sql_field;
  char buf[NAME_LEN*2+2];		 // table name plus field name plus 2
  int i,j,num_fields;
  DBUG_ENTER("build_completion_hash");

1471
  if (status.batch || quick || !current_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1472 1473 1474 1475 1476 1477 1478
    DBUG_VOID_RETURN;			// We don't need completion in batches

  /* hash SQL commands */
  while (cmd->name) {
    add_word(&ht,(char*) cmd->name);
    cmd++;
  }
1479
  if (!rehash)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1480 1481
    DBUG_VOID_RETURN;

1482 1483 1484 1485 1486 1487
  /* Free old used memory */
  if (field_names)
    field_names=0;
  completion_hash_clean(&ht);
  free_root(&hash_mem_root,MYF(0));

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1488 1489 1490
  /* hash MySQL functions (to be implemented) */

  /* hash all database names */
1491 1492
  if (mysql_query(&mysql,"show databases") == 0)
  {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1493 1494 1495 1496 1497
    if (!(databases = mysql_store_result(&mysql)))
      put_info(mysql_error(&mysql),INFO_INFO);
    else
    {
      while ((database_row=mysql_fetch_row(databases)))
1498 1499 1500 1501 1502 1503
      {
	char *str=strdup_root(&hash_mem_root, (char*) database_row[0]);
	if (str)
	  add_word(&ht,(char*) str);
      }
      mysql_free_result(databases);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
    }
  }
  /* hash all table names */
  if (mysql_query(&mysql,"show tables")==0)
  {
    if (!(tables = mysql_store_result(&mysql)))
      put_info(mysql_error(&mysql),INFO_INFO);
    else
    {
      if (mysql_num_rows(tables) > 0 && !opt_silent && write_info)
      {
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
1515
	tee_fprintf(stdout, "\
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1516 1517 1518 1519 1520
Reading table information for completion of table and column names\n\
You can turn off this feature to get a quicker startup with -A\n\n");
      }
      while ((table_row=mysql_fetch_row(tables)))
      {
1521 1522 1523 1524
	char *str=strdup_root(&hash_mem_root, (char*) table_row[0]);
	if (str &&
	    !completion_hash_exists(&ht,(char*) str, (uint) strlen(str)))
	  add_word(&ht,str);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1525 1526 1527 1528 1529
      }
    }
  }

  /* hash all field names, both with the table prefix and without it */
1530 1531
  if (!tables)					/* no tables */
  {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1532 1533 1534
    DBUG_VOID_RETURN;
  }
  mysql_data_seek(tables,0);
1535 1536 1537 1538
  if (!(field_names= (char ***) alloc_root(&hash_mem_root,sizeof(char **) *
					   (uint) (mysql_num_rows(tables)+1))))
  {
    mysql_free_result(tables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1539
    DBUG_VOID_RETURN;
1540
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1541 1542 1543 1544 1545 1546
  i=0;
  while ((table_row=mysql_fetch_row(tables)))
  {
    if ((fields=mysql_list_fields(&mysql,(const char*) table_row[0],NullS)))
    {
      num_fields=mysql_num_fields(fields);
1547 1548 1549
      if (!(field_names[i] = (char **) alloc_root(&hash_mem_root,
						  sizeof(char *) *
						  (num_fields*2+1))))
1550 1551 1552 1553
      {
        mysql_free_result(fields);
        break;
      }
1554
      field_names[i][num_fields*2]= '\0';
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1555 1556 1557
      j=0;
      while ((sql_field=mysql_fetch_field(fields)))
      {
1558
	sprintf(buf,"%.64s.%.64s",table_row[0],sql_field->name);
1559
	field_names[i][j] = strdup_root(&hash_mem_root,buf);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1560
	add_word(&ht,field_names[i][j]);
1561 1562
	field_names[i][num_fields+j] = strdup_root(&hash_mem_root,
						   sql_field->name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1563
	if (!completion_hash_exists(&ht,field_names[i][num_fields+j],
1564
				    (uint) strlen(field_names[i][num_fields+j])))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1565 1566 1567
	  add_word(&ht,field_names[i][num_fields+j]);
	j++;
      }
1568
      mysql_free_result(fields);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1569 1570
    }
    else
1571
    {
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
1572 1573
      tee_fprintf(stdout,
		  "Didn't find any fields in table '%s'\n",table_row[0]);
1574
      field_names[i]= 0;
1575
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1576 1577
    i++;
  }
1578
  mysql_free_result(tables);
1579
  field_names[i]=0;				// End pointer
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1580 1581 1582 1583 1584 1585 1586
  DBUG_VOID_RETURN;
}

	/* for gnu readline */

#ifndef HAVE_INDEX
extern "C" {
1587
extern char *index(const char *,int c),*rindex(const char *,int);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1588

1589
char *index(const char *s,int c)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1590 1591 1592 1593 1594 1595 1596 1597
{
  for (;;)
  {
     if (*s == (char) c) return (char*) s;
     if (!*s++) return NullS;
  }
}

1598
char *rindex(const char *s,int c)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609
{
  reg3 char *t;

  t = NullS;
  do if (*s == (char) c) t = (char*) s; while (*s++);
  return (char*) t;
}
}
#endif
#endif /* HAVE_READLINE */

1610

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1611 1612
static int reconnect(void)
{
1613
  if (opt_reconnect)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1614 1615 1616
  {
    put_info("No connection. Trying to reconnect...",INFO_INFO);
    (void) com_connect((String *) 0, 0);
1617 1618
    if (rehash)
      com_rehash(NULL, NULL);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1619 1620 1621 1622 1623 1624
  }
  if (!connected)
    return put_info("Can't connect to the server\n",INFO_ERROR);
  return 0;
}

1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
static void get_current_db()
{
  MYSQL_RES *res;

  my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
  current_db= NULL;
  /* In case of error below current_db will be NULL */
  if (!mysql_query(&mysql, "SELECT DATABASE()") &&
      (res= mysql_use_result(&mysql)))
  {
    MYSQL_ROW row= mysql_fetch_row(res);
    if (row[0])
      current_db= my_strdup(row[0], MYF(MY_WME));
    mysql_free_result(res);
  }
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1641 1642 1643 1644 1645

/***************************************************************************
 The different commands
***************************************************************************/

1646 1647 1648 1649 1650
int mysql_real_query_for_lazy(const char *buf, int length)
{
  for (uint retry=0;; retry++)
  {
    if (!mysql_real_query(&mysql,buf,length))
1651
      return 0;
1652
    int error= put_error(&mysql);
1653
    if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 ||
1654
      !opt_reconnect)
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666
      return error;
    if (reconnect())
      return error;
  }
}

int mysql_store_result_for_lazy(MYSQL_RES **result)
{
  if ((*result=mysql_store_result(&mysql)))
    return 0;

  if (mysql_error(&mysql)[0])
1667
    return put_error(&mysql);
1668 1669 1670
  return 0;
}

vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1671 1672 1673 1674 1675
static void print_help_item(MYSQL_ROW *cur, int num_name, int num_cat, char *last_char)
{
  char ccat= (*cur)[num_cat][0];
  if (*last_char != ccat)
  {
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
1676
    put_info(ccat == 'Y' ? "categories:" : "topics:", INFO_INFO);
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1677 1678 1679 1680
    *last_char= ccat;
  }
  tee_fprintf(PAGER, "   %s\n", (*cur)[num_name]);
}
1681

1682

1683
static int com_server_help(String *buffer __attribute__((unused)),
1684
			   char *line __attribute__((unused)), char *help_arg)
1685 1686 1687 1688
{
  MYSQL_ROW cur;
  const char *server_cmd= buffer->ptr();
  char cmd_buf[100];
1689 1690
  MYSQL_RES *result;
  int error;
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1691
  
1692
  if (help_arg[0] != '\'')
1693
  {
1694
    (void) strxnmov(cmd_buf, sizeof(cmd_buf), "help '", help_arg, "'", NullS);
1695 1696
    server_cmd= cmd_buf;
  }
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1697
  
1698 1699 1700 1701 1702 1703 1704 1705 1706
  if (!status.batch)
  {
    old_buffer= *buffer;
    old_buffer.copy();
  }

  if (!connected && reconnect())
    return 1;

1707
  if ((error= mysql_real_query_for_lazy(server_cmd,(int)strlen(server_cmd))) ||
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1708
      (error= mysql_store_result_for_lazy(&result)))
1709 1710 1711 1712
    return error;

  if (result)
  {
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1713 1714
    unsigned int num_fields= mysql_num_fields(result);
    my_ulonglong num_rows= mysql_num_rows(result);
monty@mysql.com's avatar
monty@mysql.com committed
1715
    mysql_fetch_fields(result);
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1716
    if (num_fields==3 && num_rows==1)
1717 1718
    {
      if (!(cur= mysql_fetch_row(result)))
1719 1720 1721 1722
      {
	error= -1;
	goto err;
      }
1723 1724

      init_pager();
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1725 1726 1727 1728 1729
      tee_fprintf(PAGER,   "Name: \'%s\'\n", cur[0]);
      tee_fprintf(PAGER,   "Description:\n%s", cur[1]);
      if (cur[2] && *((char*)cur[2]))
	tee_fprintf(PAGER, "Examples:\n%s", cur[2]);
      tee_fprintf(PAGER,   "\n");
1730 1731
      end_pager();
    }
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1732
    else if (num_fields >= 2 && num_rows)
1733 1734
    {
      init_pager();
1735 1736
      char last_char= 0;

1737
      int num_name= 0, num_cat= 0;
1738 1739 1740
      LINT_INIT(num_name);
      LINT_INIT(num_cat);

vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1741
      if (num_fields == 2)
1742
      {
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
1743
	put_info("Many help items for your request exist.", INFO_INFO);
paul@frost.snake.net's avatar
paul@frost.snake.net committed
1744
	put_info("To make a more specific request, please type 'help <item>',\nwhere <item> is one of the following", INFO_INFO);
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1745 1746
	num_name= 0;
	num_cat= 1;
1747
      }
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1748 1749
      else if ((cur= mysql_fetch_row(result)))
      {
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
1750
	tee_fprintf(PAGER, "You asked for help about help category: \"%s\"\n", cur[0]);
paul@frost.snake.net's avatar
paul@frost.snake.net committed
1751
	put_info("For more information, type 'help <item>', where <item> is one of the following", INFO_INFO);
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1752 1753 1754 1755
	num_name= 1;
	num_cat= 2;
	print_help_item(&cur,1,2,&last_char);
      }
1756

vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1757 1758
      while ((cur= mysql_fetch_row(result)))
	print_help_item(&cur,num_name,num_cat,&last_char);
1759 1760 1761 1762 1763
      tee_fprintf(PAGER, "\n");
      end_pager();
    }
    else
    {
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1764
      put_info("\nNothing found", INFO_INFO);
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
1765
      put_info("Please try to run 'help contents' for a list of all accessible topics\n", INFO_INFO);
1766 1767 1768
    }
  }

1769
err:
1770 1771 1772 1773
  mysql_free_result(result);
  return error;
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1774
static int
1775 1776
com_help(String *buffer __attribute__((unused)),
	 char *line __attribute__((unused)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1777
{
1778 1779
  reg1 int i, j;
  char * help_arg= strchr(line,' '), buff[32], *end;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1780

1781 1782
  if (help_arg)
    return com_server_help(buffer,line,help_arg+1);
1783

paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
1784 1785 1786
  put_info("\nFor the complete MySQL Manual online, visit:\n   http://www.mysql.com/documentation\n", INFO_INFO);
  put_info("For info on technical support from MySQL developers, visit:\n   http://www.mysql.com/support\n", INFO_INFO);
  put_info("For info on MySQL books, utilities, consultants, etc., visit:\n   http://www.mysql.com/portal\n", INFO_INFO);
1787 1788 1789 1790
  put_info("List of all MySQL commands:", INFO_INFO);
  if (!named_cmds)
    put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO);
  for (i = 0; commands[i].name; i++)
1791
  {
1792
    end= strmov(buff, commands[i].name);
1793
    for (j= (int)strlen(commands[i].name); j < 10; j++)
1794
      end= strmov(end, " ");
1795
    if (commands[i].func)
1796
      tee_fprintf(stdout, "%s(\\%c) %s\n", buff,
1797
		  commands[i].cmd_char, commands[i].doc);
1798
  }
1799
  if (connected && mysql_get_server_version(&mysql) >= 40100)
serg@serg.mylan's avatar
serg@serg.mylan committed
1800
    put_info("\nFor server side help, type 'help contents'\n", INFO_INFO);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1801 1802 1803 1804 1805 1806 1807 1808
  return 0;
}


	/* ARGSUSED */
static int
com_clear(String *buffer,char *line __attribute__((unused)))
{
1809 1810 1811 1812
#ifdef HAVE_READLINE
  if (status.add_to_history)
    fix_history(buffer);
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1813 1814 1815 1816 1817 1818
  buffer->length(0);
  return 0;
}


/*
1819 1820 1821 1822
  Execute command
  Returns: 0  if ok
          -1 if not fatal error
	  1  if fatal error
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1823 1824 1825 1826 1827 1828
*/


static int
com_go(String *buffer,char *line __attribute__((unused)))
{
1829
  char		buff[200], time_buff[32], *pos;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1830
  MYSQL_RES	*result;
1831
  ulong		timer, warnings;
1832 1833
  uint		error= 0;
  int           err= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1834 1835 1836 1837 1838 1839 1840

  if (!status.batch)
  {
    old_buffer= *buffer;			// Save for edit command
    old_buffer.copy();
  }

1841
  /* Remove garbage for nicer messages */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854
  LINT_INIT(buff[0]);
  remove_cntrl(*buffer);

  if (buffer->is_empty())
  {
    if (status.batch)				// Ignore empty quries
      return 0;
    return put_info("No query specified\n",INFO_ERROR);

  }
  if (!connected && reconnect())
  {
    buffer->length(0);				// Remove query on error
1855
    return opt_reconnect ? -1 : 1;          // Fatal error
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1856 1857 1858 1859 1860
  }
  if (verbose)
    (void) com_print(buffer,0);

  if (skip_updates &&
1861
      (buffer->length() < 4 || my_strnncoll(charset_info,
1862 1863
					    (const uchar*)buffer->ptr(),4,
					    (const uchar*)"SET ",4)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1864 1865 1866 1867 1868 1869
  {
    (void) put_info("Ignoring query to other database",INFO_INFO);
    return 0;
  }

  timer=start_timer();
1870 1871

  error= mysql_real_query_for_lazy(buffer->ptr(),buffer->length());
1872 1873 1874 1875 1876 1877 1878 1879 1880 1881

#ifdef HAVE_READLINE
  if (status.add_to_history) 
  {  
    buffer->append(vertical ? "\\G" : delimiter);
    /* Append final command onto history */
    fix_history(buffer);
  }
#endif

1882
  if (error)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1883
  {
1884 1885
    buffer->length(0); // Remove query on error
    return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1886 1887 1888 1889
  }
  error=0;
  buffer->length(0);

1890
  do
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1891
  {
1892
    if (quick)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1893
    {
1894 1895
      if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql))
	return put_error(&mysql);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1896 1897 1898
    }
    else
    {
1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913
      error= mysql_store_result_for_lazy(&result);
      if (error)
	return error;
    }

    if (verbose >= 3 || !opt_silent)
      mysql_end_timer(timer,time_buff);
    else
      time_buff[0]=0;
    if (result)
    {
      if (!mysql_num_rows(result) && ! quick)
      {
	strmov(buff, "Empty set");
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1914
      else
1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931
      {
	init_pager();
	if (opt_html)
	  print_table_data_html(result);
	else if (opt_xml)
	  print_table_data_xml(result);
	else if (vertical)
	  print_table_data_vertically(result);
	else if (opt_silent && verbose <= 2 && !output_tables)
	  print_tab_data(result);
	else
	  print_table_data(result);
	sprintf(buff,"%ld %s in set",
		(long) mysql_num_rows(result),
		(long) mysql_num_rows(result) == 1 ? "row" : "rows");
	end_pager();
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1932
    }
1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944
    else if (mysql_affected_rows(&mysql) == ~(ulonglong) 0)
      strmov(buff,"Query OK");
    else
      sprintf(buff,"Query OK, %ld %s affected",
	      (long) mysql_affected_rows(&mysql),
	      (long) mysql_affected_rows(&mysql) == 1 ? "row" : "rows");

    pos=strend(buff);
    if ((warnings= mysql_warning_count(&mysql)))
    {
      *pos++= ',';
      *pos++= ' ';
1945
      pos=int10_to_str(warnings, pos, 10);
1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960
      pos=strmov(pos, " warning");
      if (warnings != 1)
	*pos++= 's';
    }
    strmov(pos, time_buff);
    put_info(buff,INFO_RESULT);
    if (mysql_info(&mysql))
      put_info(mysql_info(&mysql),INFO_RESULT);
    put_info("",INFO_RESULT);			// Empty row

    if (result && !mysql_eof(result))	/* Something wrong when using quick */
      error= put_error(&mysql);
    else if (unbuffered)
      fflush(stdout);
    mysql_free_result(result);
1961 1962 1963
  } while (!(err= mysql_next_result(&mysql)));
  if (err >= 1)
    error= put_error(&mysql);
1964

ramil@mysql.com's avatar
ramil@mysql.com committed
1965 1966
  if (!error && !status.batch && 
      (mysql.server_status & SERVER_STATUS_DB_DROPPED))
1967 1968
    get_current_db();

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1969 1970 1971
  return error;				/* New command follows */
}

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
1972 1973 1974

static void init_pager()
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1975
#ifdef USE_POPEN
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990
  if (!opt_nopager)
  {
    if (!(PAGER= popen(pager, "w")))
    {
      tee_fprintf(stdout, "popen() failed! defaulting PAGER to stdout!\n");
      PAGER= stdout;
    }
  }
  else
#endif
    PAGER= stdout;
}

static void end_pager()
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1991
#ifdef USE_POPEN
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
1992 1993 1994 1995 1996
  if (!opt_nopager)
    pclose(PAGER);
#endif
}

1997

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1998
static void init_tee(const char *file_name)
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
1999
{
2000
  FILE* new_outfile;
2001
  if (opt_outfile)
2002
    end_tee();
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2003 2004 2005 2006 2007
  if (!(new_outfile= my_fopen(file_name, O_APPEND | O_WRONLY, MYF(MY_WME))))
  {
    tee_fprintf(stdout, "Error logging to file '%s'\n", file_name);
    return;
  }
2008
  OUTFILE = new_outfile;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2009 2010 2011 2012
  strmake(outfile, file_name, FN_REFLEN-1);
  tee_fprintf(stdout, "Logging to file '%s'\n", file_name);
  opt_outfile= 1;
  return;
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2013 2014
}

2015

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2016 2017 2018
static void end_tee()
{
  my_fclose(OUTFILE, MYF(0));
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2019
  OUTFILE= 0;
2020
  opt_outfile= 0;
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2021 2022 2023
  return;
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034
static int
com_ego(String *buffer,char *line)
{
  int result;
  bool oldvertical=vertical;
  vertical=1;
  result=com_go(buffer,line);
  vertical=oldvertical;
  return result;
}

2035 2036 2037 2038 2039 2040
static void
print_field_types(MYSQL_RES *result)
{
  MYSQL_FIELD	*field;  
  while ((field = mysql_fetch_field(result)))
  {
2041
    tee_fprintf(PAGER,"Catalog:    '%s'\nDatabase:   '%s'\nTable:      '%s'\nName:       '%s'\nType:       %d\nLength:     %ld\nMax length: %ld\nIs_null:    %d\nFlags:      %u\nDecimals:   %u\n\n",
2042
		field->catalog, field->db, field->table, field->name,
2043
		(int) field->type,
2044 2045
		field->length, field->max_length,
		!IS_NOT_NULL(field->flags),
2046 2047 2048 2049 2050
		field->flags, field->decimals);
  }
  tee_puts("", PAGER);
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2051 2052 2053 2054 2055 2056 2057 2058 2059 2060

static void
print_table_data(MYSQL_RES *result)
{
  String separator(256);
  MYSQL_ROW	cur;
  MYSQL_FIELD	*field;
  bool		*num_flag;

  num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result));
2061 2062 2063 2064 2065
  if (info_flag)
  {
    print_field_types(result);
    mysql_field_seek(result,0);
  }
2066
  separator.copy("+",1,charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2067 2068
  while ((field = mysql_fetch_field(result)))
  {
2069
    uint length= column_names ? field->name_length : 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2070 2071 2072 2073 2074 2075 2076 2077 2078 2079
    if (quick)
      length=max(length,field->length);
    else
      length=max(length,field->max_length);
    if (length < 4 && !IS_NOT_NULL(field->flags))
      length=4;					// Room for "NULL"
    field->max_length=length+1;
    separator.fill(separator.length()+length+2,'-');
    separator.append('+');
  }
2080
  tee_puts(separator.c_ptr_safe(), PAGER);
2081
  if (column_names)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2082 2083
  {
    mysql_field_seek(result,0);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2084
    (void) tee_fputs("|", PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2085 2086
    for (uint off=0; (field = mysql_fetch_field(result)) ; off++)
    {
2087 2088
      tee_fprintf(PAGER, " %-*s|",(int) min(field->max_length,
                                            MAX_COLUMN_LENGTH),
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2089
		  field->name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2090 2091
      num_flag[off]= IS_NUM(field->type);
    }
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2092 2093
    (void) tee_fputs("\n", PAGER);
    tee_puts(separator.c_ptr(), PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2094 2095
  }

2096
  while ((cur= mysql_fetch_row(result)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2097
  {
bar@mysql.com's avatar
bar@mysql.com committed
2098
    ulong *lengths= mysql_fetch_lengths(result);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2099
    (void) tee_fputs("|", PAGER);
2100 2101
    mysql_field_seek(result, 0);
    for (uint off= 0; off < mysql_num_fields(result); off++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2102
    {
2103 2104
      const char *str= cur[off] ? cur[off] : "NULL";
      field= mysql_fetch_field(result);
bar@mysql.com's avatar
bar@mysql.com committed
2105 2106
      uint maxlength= field->max_length;
      if (maxlength > MAX_COLUMN_LENGTH)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2107
      {
2108 2109
	tee_fputs(str, PAGER);
	tee_fputs(" |", PAGER);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2110 2111
      }
      else
bar@mysql.com's avatar
bar@mysql.com committed
2112 2113 2114 2115 2116 2117 2118
      {
        uint currlength= (uint) lengths[off];
        uint numcells= charset_info->cset->numcells(charset_info, 
                                                    str, str + currlength);
        tee_fprintf(PAGER, num_flag[off] ? "%*s |" : " %-*s|",
                    maxlength + currlength - numcells, str);
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2119
    }
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2120
    (void) tee_fputs("\n", PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2121
  }
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2122
  tee_puts(separator.c_ptr(), PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2123 2124 2125
  my_afree((gptr) num_flag);
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2126

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2127 2128 2129
static void
print_table_data_html(MYSQL_RES *result)
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2130 2131
  MYSQL_ROW	cur;
  MYSQL_FIELD	*field;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2132 2133

  mysql_field_seek(result,0);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2134
  (void) tee_fputs("<TABLE BORDER=1><TR>", PAGER);
2135
  if (column_names)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2136 2137 2138
  {
    while((field = mysql_fetch_field(result)))
    {
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2139 2140 2141
      tee_fprintf(PAGER, "<TH>%s</TH>", (field->name ? 
					 (field->name[0] ? field->name : 
					  " &nbsp; ") : "NULL"));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2142
    }
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2143
    (void) tee_fputs("</TR>", PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2144 2145 2146
  }
  while ((cur = mysql_fetch_row(result)))
  {
2147
    ulong *lengths=mysql_fetch_lengths(result);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2148
    (void) tee_fputs("<TR>", PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2149 2150
    for (uint i=0; i < mysql_num_fields(result); i++)
    {
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2151
      (void) tee_fputs("<TD>", PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2152
      safe_put_field(cur[i],lengths[i]);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2153
      (void) tee_fputs("</TD>", PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2154
    }
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2155
    (void) tee_fputs("</TR>", PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2156
  }
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2157
  (void) tee_fputs("</TABLE>", PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2158 2159 2160
}


2161 2162 2163 2164 2165 2166 2167 2168
static void
print_table_data_xml(MYSQL_RES *result)
{
  MYSQL_ROW   cur;
  MYSQL_FIELD *fields;

  mysql_field_seek(result,0);

2169
  tee_fputs("<?xml version=\"1.0\"?>\n\n<resultset statement=\"", PAGER);
2170
  xmlencode_print(glob_buffer.ptr(), (int)strlen(glob_buffer.ptr()));
2171
  tee_fputs("\">", PAGER);
2172 2173 2174 2175

  fields = mysql_fetch_fields(result);
  while ((cur = mysql_fetch_row(result)))
  {
2176
    ulong *lengths=mysql_fetch_lengths(result);
2177 2178 2179
    (void) tee_fputs("\n  <row>\n", PAGER);
    for (uint i=0; i < mysql_num_fields(result); i++)
    {
2180
      tee_fprintf(PAGER, "\t<field name=\"");
2181
      xmlencode_print(fields[i].name, (uint) strlen(fields[i].name));
2182
      tee_fprintf(PAGER, "\">");
2183
      xmlencode_print(cur[i], lengths[i]);
2184
      tee_fprintf(PAGER, "</field>\n");
2185 2186 2187 2188 2189 2190
    }
    (void) tee_fputs("  </row>\n", PAGER);
  }
  (void) tee_fputs("</resultset>\n", PAGER);
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2191 2192 2193 2194 2195 2196 2197 2198 2199 2200

static void
print_table_data_vertically(MYSQL_RES *result)
{
  MYSQL_ROW	cur;
  uint		max_length=0;
  MYSQL_FIELD	*field;

  while ((field = mysql_fetch_field(result)))
  {
2201
    uint length= field->name_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2202 2203 2204 2205 2206 2207 2208 2209 2210
    if (length > max_length)
      max_length= length;
    field->max_length=length;
  }

  mysql_field_seek(result,0);
  for (uint row_count=1; (cur= mysql_fetch_row(result)); row_count++)
  {
    mysql_field_seek(result,0);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2211 2212
    tee_fprintf(PAGER, 
		"*************************** %d. row ***************************\n", row_count);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2213 2214 2215
    for (uint off=0; off < mysql_num_fields(result); off++)
    {
      field= mysql_fetch_field(result);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2216 2217
      tee_fprintf(PAGER, "%*s: ",(int) max_length,field->name);
      tee_fprintf(PAGER, "%s\n",cur[off] ? (char*) cur[off] : "NULL");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2218 2219 2220 2221
    }
  }
}

2222

2223
static const char
2224 2225
*array_value(const char **array, char key)
{
2226
  int x;
2227 2228 2229
  for (x= 0; array[x]; x+= 2)
    if (*array[x] == key)
      return array[x + 1];
2230 2231 2232
  return 0;
}

2233

2234
static void
2235
xmlencode_print(const char *src, uint length)
2236
{
2237 2238 2239
  if (!src)
    tee_fputs("NULL", PAGER);
  else
2240
  {
2241 2242 2243 2244 2245 2246 2247 2248 2249
    for (const char *p = src; *p && length; *p++, length--)
    {
      const char *t;
      if ((t = array_value(xmlmeta, *p)))
	tee_fputs(t, PAGER);
      else
	tee_putc(*p, PAGER);
    }
  }
2250
}
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2251

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2252 2253 2254 2255 2256

static void
safe_put_field(const char *pos,ulong length)
{
  if (!pos)
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2257
    tee_fputs("NULL", PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2258 2259 2260
  else
  {
    if (opt_raw_data)
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2261
      tee_fputs(pos, PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2262 2263 2264 2265
    else for (const char *end=pos+length ; pos != end ; pos++)
    {
#ifdef USE_MB
      int l;
2266 2267
      if (use_mb(charset_info) &&
          (l = my_ismbchar(charset_info, pos, end)))
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2268
      {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2269
	  while (l--)
2270
	    tee_putc(*pos++, PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2271 2272 2273 2274 2275
	  pos--;
	  continue;
      }
#endif
      if (!*pos)
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2276
	tee_fputs("\\0", PAGER); // This makes everything hard
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2277
      else if (*pos == '\t')
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2278
	tee_fputs("\\t", PAGER); // This would destroy tab format
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2279
      else if (*pos == '\n')
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2280
	tee_fputs("\\n", PAGER); // This too
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2281
      else if (*pos == '\\')
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2282
	tee_fputs("\\\\", PAGER);
2283
	else
2284
	tee_putc(*pos, PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296
    }
  }
}


static void
print_tab_data(MYSQL_RES *result)
{
  MYSQL_ROW	cur;
  MYSQL_FIELD	*field;
  ulong		*lengths;

2297
  if (opt_silent < 2 && column_names)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2298 2299 2300 2301 2302
  {
    int first=0;
    while ((field = mysql_fetch_field(result)))
    {
      if (first++)
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2303 2304
	(void) tee_fputs("\t", PAGER);
      (void) tee_fputs(field->name, PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2305
    }
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2306
    (void) tee_fputs("\n", PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2307 2308 2309 2310 2311 2312 2313
  }
  while ((cur = mysql_fetch_row(result)))
  {
    lengths=mysql_fetch_lengths(result);
    safe_put_field(cur[0],lengths[0]);
    for (uint off=1 ; off < mysql_num_fields(result); off++)
    {
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2314
      (void) tee_fputs("\t", PAGER);
2315
      safe_put_field(cur[off], lengths[off]);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2316
    }
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2317
    (void) tee_fputs("\n", PAGER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2318 2319 2320
  }
}

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2321 2322 2323 2324 2325 2326 2327
static int
com_tee(String *buffer, char *line __attribute__((unused)))
{
  char file_name[FN_REFLEN], *end, *param;

  if (status.batch)
    return 0;
2328
  while (my_isspace(charset_info,*line))
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2329 2330 2331 2332 2333
    line++;
  if (!(param = strchr(line, ' '))) // if outfile wasn't given, use the default
  {
    if (!strlen(outfile))
    {
2334
      printf("No previous outfile available, you must give a filename!\n");
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2335 2336
      return 0;
    }
2337 2338 2339 2340 2341 2342 2343
    else if (opt_outfile)
    {
      tee_fprintf(stdout, "Currently logging to file '%s'\n", outfile);
      return 0;
    }
    else
      param = outfile;			//resume using the old outfile
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2344
  }
2345 2346

  /* eliminate the spaces before the parameters */
2347
  while (my_isspace(charset_info,*param))
2348 2349 2350
    param++;
  end= strmake(file_name, param, sizeof(file_name) - 1);
  /* remove end space from command line */
2351 2352
  while (end > file_name && (my_isspace(charset_info,end[-1]) || 
			     my_iscntrl(charset_info,end[-1])))
2353 2354
    end--;
  end[0]= 0;
2355
  if (end == file_name)
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2356 2357 2358 2359
  {
    printf("No outfile specified!\n");
    return 0;
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2360
  init_tee(file_name);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2361 2362 2363
  return 0;
}

2364

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2365 2366 2367 2368 2369 2370 2371 2372 2373 2374
static int
com_notee(String *buffer __attribute__((unused)),
	  char *line __attribute__((unused)))
{
  if (opt_outfile)
    end_tee();
  tee_fprintf(stdout, "Outfile disabled.\n");
  return 0;
}

2375
/*
2376
  Sorry, this command is not available in Windows.
2377 2378
*/

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2379
#ifdef USE_POPEN
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2380 2381 2382 2383 2384 2385 2386
static int
com_pager(String *buffer, char *line __attribute__((unused)))
{
  char pager_name[FN_REFLEN], *end, *param;

  if (status.batch)
    return 0;
2387 2388
  /* Skip spaces in front of the pager command */
  while (my_isspace(charset_info, *line))
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2389
    line++;
2390 2391 2392 2393 2394 2395
  /* Skip the pager command */
  param= strchr(line, ' ');
  /* Skip the spaces between the command and the argument */
  while (param && my_isspace(charset_info, *param))
    param++;
  if (!param || !strlen(param)) // if pager was not given, use the default
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2396
  {
2397
    if (!default_pager_set)
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2398
    {
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2399
      tee_fprintf(stdout, "Default pager wasn't set, using stdout.\n");
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2400 2401 2402 2403 2404 2405 2406 2407 2408
      opt_nopager=1;
      strmov(pager, "stdout");
      PAGER= stdout;
      return 0;
    }
    strmov(pager, default_pager);
  }
  else
  {
2409
    end= strmake(pager_name, param, sizeof(pager_name)-1);
2410 2411
    while (end > pager_name && (my_isspace(charset_info,end[-1]) || 
                                my_iscntrl(charset_info,end[-1])))
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2412 2413 2414
      end--;
    end[0]=0;
    strmov(pager, pager_name);
2415
    strmov(default_pager, pager_name);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2416 2417
  }
  opt_nopager=0;
2418
  tee_fprintf(stdout, "PAGER set to '%s'\n", pager);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2419 2420 2421
  return 0;
}

2422

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2423 2424 2425 2426 2427 2428
static int
com_nopager(String *buffer __attribute__((unused)),
	    char *line __attribute__((unused)))
{
  strmov(pager, "stdout");
  opt_nopager=1;
2429
  PAGER= stdout;
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2430 2431 2432
  tee_fprintf(stdout, "PAGER set to stdout\n");
  return 0;
}
2433
#endif
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2434

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2435

2436
/*
2437
  Sorry, you can't send the result to an editor in Win32
2438 2439
*/

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2440
#ifdef USE_POPEN
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2441 2442 2443
static int
com_edit(String *buffer,char *line __attribute__((unused)))
{
2444
  char	filename[FN_REFLEN],buff[160];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2445 2446 2447
  int	fd,tmp;
  const char *editor;

2448 2449
  if ((fd=create_temp_file(filename,NullS,"sql", O_CREAT | O_WRONLY,
			   MYF(MY_WME))) < 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478
    goto err;
  if (buffer->is_empty() && !old_buffer.is_empty())
    (void) my_write(fd,(byte*) old_buffer.ptr(),old_buffer.length(),
		    MYF(MY_WME));
  else
    (void) my_write(fd,(byte*) buffer->ptr(),buffer->length(),MYF(MY_WME));
  (void) my_close(fd,MYF(0));

  if (!(editor = (char *)getenv("EDITOR")) &&
      !(editor = (char *)getenv("VISUAL")))
    editor = "vi";
  strxmov(buff,editor," ",filename,NullS);
  (void) system(buff);

  MY_STAT stat_arg;
  if (!my_stat(filename,&stat_arg,MYF(MY_WME)))
    goto err;
  if ((fd = my_open(filename,O_RDONLY, MYF(MY_WME))) < 0)
    goto err;
  (void) buffer->alloc((uint) stat_arg.st_size);
  if ((tmp=read(fd,(char*) buffer->ptr(),buffer->alloced_length())) >= 0L)
    buffer->length((uint) tmp);
  else
    buffer->length(0);
  (void) my_close(fd,MYF(0));
  (void) my_delete(filename,MYF(MY_WME));
err:
  return 0;
}
2479 2480
#endif

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2481 2482 2483 2484 2485 2486 2487

/* If arg is given, exit without errors. This happens on command 'quit' */

static int
com_quit(String *buffer __attribute__((unused)),
	 char *line __attribute__((unused)))
{
monty@mysql.com's avatar
monty@mysql.com committed
2488 2489
  /* let the screen auto close on a normal shutdown */
  NETWARE_SET_SCREEN_MODE(SCR_AUTOCLOSE_ON_EXIT);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2490 2491 2492 2493 2494 2495 2496 2497 2498
  status.exit_status=0;
  return 1;
}

static int
com_rehash(String *buffer __attribute__((unused)),
	 char *line __attribute__((unused)))
{
#ifdef HAVE_READLINE
2499
  build_completion_hash(1, 0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2500 2501 2502 2503
#endif
  return 0;
}

2504

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2505
#ifdef USE_POPEN
2506 2507 2508 2509
static int
com_shell(String *buffer, char *line __attribute__((unused)))
{
  char *shell_cmd;
2510 2511

  /* Skip space from line begin */
serg@serg.mylan's avatar
serg@serg.mylan committed
2512
  while (my_isspace(charset_info, *line))
2513
    line++;
2514 2515 2516 2517 2518
  if (!(shell_cmd = strchr(line, ' ')))
  {
    put_info("Usage: \\! shell-command", INFO_ERROR);
    return -1;
  }
2519 2520 2521 2522 2523
  /*
    The output of the shell command does not
    get directed to the pager or the outfile
  */
  if (system(shell_cmd) == -1)
2524 2525 2526 2527 2528 2529 2530 2531 2532
  {
    put_info(strerror(errno), INFO_ERROR, errno);
    return -1;
  }
  return 0;
}
#endif


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2533 2534 2535
static int
com_print(String *buffer,char *line __attribute__((unused)))
{
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2536 2537
  tee_puts("--------------", stdout);
  (void) tee_fputs(buffer->c_ptr(), stdout);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2538
  if (!buffer->length() || (*buffer)[buffer->length()-1] != '\n')
2539
    tee_putc('\n', stdout);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2540
  tee_puts("--------------\n", stdout);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2541 2542 2543 2544 2545 2546 2547
  return 0;					/* If empty buffer */
}

	/* ARGSUSED */
static int
com_connect(String *buffer, char *line)
{
2548
  char *tmp, buff[256];
2549
  bool save_rehash= rehash;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2550 2551
  int error;

2552
  bzero(buff, sizeof(buff));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2553 2554
  if (buffer)
  {
2555 2556 2557
    strmov(buff, line);
    tmp= get_arg(buff, 0);
    if (tmp && *tmp)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2558
    {
2559 2560 2561 2562
      my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
      current_db= my_strdup(tmp, MYF(MY_WME));
      tmp= get_arg(buff, 1);
      if (tmp)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2563 2564 2565 2566 2567 2568
      {
	my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
	current_host=my_strdup(tmp,MYF(MY_WME));
      }
    }
    else
2569
      rehash= 0;				// Quick re-connect
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2570 2571 2572
    buffer->length(0);				// command used
  }
  else
2573
    rehash= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2574
  error=sql_connect(current_host,current_db,current_user,opt_password,0);
2575
  rehash= save_rehash;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2576 2577 2578

  if (connected)
  {
2579
    sprintf(buff,"Connection id:    %lu",mysql_thread_id(&mysql));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2580
    put_info(buff,INFO_INFO);
2581
    sprintf(buff,"Current database: %.128s\n",
2582
	    current_db ? current_db : "*** NONE ***");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597
    put_info(buff,INFO_INFO);
  }
  return error;
}


static int com_source(String *buffer, char *line)
{
  char source_name[FN_REFLEN], *end, *param;
  LINE_BUFFER *line_buff;
  int error;
  STATUS old_status;
  FILE *sql_file;

  /* Skip space from file name */
2598
  while (my_isspace(charset_info,*line))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2599
    line++;
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2600 2601 2602
  if (!(param = strchr(line, ' ')))		// Skip command name
    return put_info("Usage: \\. <filename> | source <filename>", 
		    INFO_ERROR, 0);
2603
  while (my_isspace(charset_info,*param))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2604 2605
    param++;
  end=strmake(source_name,param,sizeof(source_name)-1);
2606 2607
  while (end > source_name && (my_isspace(charset_info,end[-1]) || 
                               my_iscntrl(charset_info,end[-1])))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2608 2609
    end--;
  end[0]=0;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2610
  unpack_filename(source_name,source_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2611
  /* open file name */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2612
  if (!(sql_file = my_fopen(source_name, O_RDONLY | O_BINARY,MYF(0))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2613 2614 2615 2616 2617 2618
  {
    char buff[FN_REFLEN+60];
    sprintf(buff,"Failed to open file '%s', error: %d", source_name,errno);
    return put_info(buff, INFO_ERROR, 0);
  }

2619
  if (!(line_buff=batch_readline_init(opt_max_allowed_packet+512,sql_file)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640
  {
    my_fclose(sql_file,MYF(0));
    return put_info("Can't initialize batch_readline", INFO_ERROR, 0);
  }

  /* Save old status */
  old_status=status;
  bfill((char*) &status,sizeof(status),(char) 0);

  status.batch=old_status.batch;		// Run in batch mode
  status.line_buff=line_buff;
  status.file_name=source_name;
  glob_buffer.length(0);			// Empty command buffer
  error=read_lines(0);				// Read lines from file
  status=old_status;				// Continue as before
  my_fclose(sql_file,MYF(0));
  batch_readline_end(line_buff);
  return error;
}


2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656
	/* ARGSUSED */
static int
com_delimiter(String *buffer __attribute__((unused)), char *line)
{
  char buff[256], *tmp;

  strmake(buff, line, sizeof(buff) - 1);
  tmp= get_arg(buff, 0);

  if (!tmp || !*tmp)
  {
    put_info("DELIMITER must be followed by a 'delimiter' character or string",
	     INFO_ERROR);
    return 0;
  }
  strmake(delimiter, tmp, sizeof(delimiter) - 1);
2657
  delimiter_length= (int)strlen(delimiter);
2658
  delimiter_str= delimiter;
2659 2660 2661
  return 0;
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2662 2663 2664 2665
	/* ARGSUSED */
static int
com_use(String *buffer __attribute__((unused)), char *line)
{
2666
  char *tmp, buff[FN_REFLEN + 1];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2667

2668
  bzero(buff, sizeof(buff));
2669
  strmov(buff, line);
2670
  tmp= get_arg(buff, 0);
2671
  if (!tmp || !*tmp)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2672
  {
2673
    put_info("USE must be followed by a database name", INFO_ERROR);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2674 2675
    return 0;
  }
2676 2677 2678 2679
  /*
    We need to recheck the current database, because it may change
    under our feet, for example if DROP DATABASE or RENAME DATABASE
    (latter one not yet available by the time the comment was written)
2680
  */
2681
  get_current_db();
2682

serg@serg.mylan's avatar
serg@serg.mylan committed
2683
  if (!current_db || cmp_database(charset_info, current_db,tmp))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2684 2685
  {
    if (one_database)
2686
      skip_updates= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2687 2688 2689 2690 2691 2692 2693
    else
    {
      /*
	reconnect once if connection is down or if connection was found to
	be down during query
      */
      if (!connected && reconnect())
2694
      return opt_reconnect ? -1 : 1;                        // Fatal error
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2695 2696 2697
      if (mysql_select_db(&mysql,tmp))
      {
	if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR)
2698
	  return put_error(&mysql);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2699 2700

	if (reconnect())
2701
        return opt_reconnect ? -1 : 1;                      // Fatal error
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2702
	if (mysql_select_db(&mysql,tmp))
2703
	  return put_error(&mysql);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2704
      }
2705 2706
      my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
      current_db=my_strdup(tmp,MYF(MY_WME));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2707
#ifdef HAVE_READLINE
2708
      build_completion_hash(rehash, 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2709 2710 2711 2712
#endif
    }
  }
  else
2713
    skip_updates= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2714 2715 2716 2717 2718
  put_info("Database changed",INFO_INFO);
  return 0;
}


2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729
/*
  Gets argument from a command on the command line. If get_next_arg is
  not defined, skips the command and returns the first argument. The
  line is modified by adding zero to the end of the argument. If
  get_next_arg is defined, then the function searches for end of string
  first, after found, returns the next argument and adds zero to the
  end. If you ever wish to use this feature, remember to initialize all
  items in the array to zero first.
*/

char *get_arg(char *line, my_bool get_next_arg)
2730
{
2731
  char *ptr, *start;
2732
  my_bool quoted= 0, valid_arg= 0;
2733
  char qtype= 0;
2734 2735

  ptr= line;
2736 2737
  if (get_next_arg)
  {
2738 2739
    for (; *ptr; ptr++) ;
    if (*(ptr + 1))
2740 2741 2742 2743 2744
      ptr++;
  }
  else
  {
    /* skip leading white spaces */
2745
    while (my_isspace(charset_info, *ptr))
2746 2747 2748
      ptr++;
    if (*ptr == '\\') // short command was used
      ptr+= 2;
2749 2750 2751
    else
      while (*ptr &&!my_isspace(charset_info, *ptr)) // skip command
        ptr++;
2752
  }
2753 2754
  if (!*ptr)
    return NullS;
2755
  while (my_isspace(charset_info, *ptr))
2756
    ptr++;
2757
  if (*ptr == '\'' || *ptr == '\"' || *ptr == '`')
2758
  {
2759
    qtype= *ptr;
2760 2761 2762
    quoted= 1;
    ptr++;
  }
2763
  for (start=ptr ; *ptr; ptr++)
2764
  {
2765
    if (*ptr == '\\' && ptr[1]) // escaped character
2766
    {
2767 2768
      // Remove the backslash
      strmov(ptr, ptr+1);
2769
    }
2770
    else if ((!quoted && *ptr == ' ') || (quoted && *ptr == qtype))
2771 2772 2773 2774 2775
    {
      *ptr= 0;
      break;
    }
  }
2776 2777
  valid_arg= ptr != start;
  return valid_arg ? start : NullS;
2778 2779 2780
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2781 2782 2783 2784
static int
sql_real_connect(char *host,char *database,char *user,char *password,
		 uint silent)
{
monty@mysql.com's avatar
monty@mysql.com committed
2785 2786 2787 2788 2789
  if (connected)
  {
    connected= 0;
    mysql_close(&mysql);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2790
  mysql_init(&mysql);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2791
  if (opt_connect_timeout)
2792 2793
  {
    uint timeout=opt_connect_timeout;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2794
    mysql_options(&mysql,MYSQL_OPT_CONNECT_TIMEOUT,
2795 2796
		  (char*) &timeout);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2797 2798
  if (opt_compress)
    mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
2799 2800
  if (opt_secure_auth)
    mysql_options(&mysql, MYSQL_SECURE_AUTH, (char *) &opt_secure_auth);
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
2801 2802
  if (using_opt_local_infile)
    mysql_options(&mysql,MYSQL_OPT_LOCAL_INFILE, (char*) &opt_local_infile);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2803 2804 2805
#ifdef HAVE_OPENSSL
  if (opt_use_ssl)
    mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
2806
		  opt_ssl_capath, opt_ssl_cipher);
2807 2808 2809 2810 2811 2812
#endif
  if (opt_protocol)
    mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
#ifdef HAVE_SMEM
  if (shared_memory_base_name)
    mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2813 2814 2815 2816 2817 2818 2819 2820 2821
#endif
  if (safe_updates)
  {
    char init_command[100];
    sprintf(init_command,
	    "SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=%lu,SQL_MAX_JOIN_SIZE=%lu",
	    select_limit,max_join_size);
    mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command);
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2822 2823
  if (default_charset_used)
    mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
2824 2825
  if (!mysql_real_connect(&mysql, host, user, password,
			  database, opt_mysql_port, opt_mysql_unix_port,
2826
			  connect_flag | CLIENT_MULTI_STATEMENTS))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2827 2828 2829 2830 2831
  {
    if (!silent ||
	(mysql_errno(&mysql) != CR_CONN_HOST_ERROR &&
	 mysql_errno(&mysql) != CR_CONNECTION_ERROR))
    {
2832
      (void) put_error(&mysql);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2833 2834 2835 2836 2837 2838
      (void) fflush(stdout);
      return ignore_errors ? -1 : 1;		// Abort
    }
    return -1;					// Retryable
  }
  connected=1;
2839
#ifndef EMBEDDED_LIBRARY
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2840
  mysql.reconnect=info_flag ? 1 : 0; // We want to know if this happens
2841 2842
#else
  mysql.reconnect= 1;
2843
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2844
#ifdef HAVE_READLINE
2845
  build_completion_hash(rehash, 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862
#endif
  return 0;
}


static int
sql_connect(char *host,char *database,char *user,char *password,uint silent)
{
  bool message=0;
  uint count=0;
  int error;
  for (;;)
  {
    if ((error=sql_real_connect(host,database,user,password,wait_flag)) >= 0)
    {
      if (count)
      {
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2863
	tee_fputs("\n", stderr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2864 2865 2866 2867 2868 2869 2870 2871 2872
	(void) fflush(stderr);
      }
      return error;
    }
    if (!wait_flag)
      return ignore_errors ? -1 : 1;
    if (!message && !silent)
    {
      message=1;
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2873
      tee_fputs("Waiting",stderr); (void) fflush(stderr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2874
    }
2875
    (void) sleep(wait_time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889
    if (!silent)
    {
      putc('.',stderr); (void) fflush(stderr);
      count++;
    }
  }
}



static int
com_status(String *buffer __attribute__((unused)),
	   char *line __attribute__((unused)))
{
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
2890
  const char *status;
2891 2892
  char buff[22];
  ulonglong id;
bar@mysql.com's avatar
bar@mysql.com committed
2893 2894
  MYSQL_RES *result;
  LINT_INIT(result);
2895

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2896
  tee_puts("--------------", stdout);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2897 2898 2899
  usage(1);					/* Print version */
  if (connected)
  {
2900
    tee_fprintf(stdout, "\nConnection id:\t\t%lu\n",mysql_thread_id(&mysql));
bar@mysql.com's avatar
bar@mysql.com committed
2901 2902 2903 2904
    /* 
      Don't remove "limit 1", 
      it is protection againts SQL_SELECT_LIMIT=0
    */
2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915
    if (!mysql_query(&mysql,"select DATABASE(), USER() limit 1") &&
	(result=mysql_use_result(&mysql)))
    {
      MYSQL_ROW cur=mysql_fetch_row(result);
      if (cur)
      {
        tee_fprintf(stdout, "Current database:\t%s\n", cur[0] ? cur[0] : "");
        tee_fprintf(stdout, "Current user:\t\t%s\n", cur[1]);
      }
      mysql_free_result(result);
    } 
2916
#ifdef HAVE_OPENSSL
2917 2918
    if (mysql.net.vio && mysql.net.vio->ssl_arg &&
	SSL_get_cipher((SSL*) mysql.net.vio->ssl_arg))
2919
      tee_fprintf(stdout, "SSL:\t\t\tCipher in use is %s\n",
2920
		  SSL_get_cipher((SSL*) mysql.net.vio->ssl_arg));
2921 2922
    else
#endif /* HAVE_OPENSSL */
2923
      tee_puts("SSL:\t\t\tNot in use", stdout);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2924 2925 2926 2927
  }
  else
  {
    vidattr(A_BOLD);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2928
    tee_fprintf(stdout, "\nNo connection\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2929 2930 2931 2932 2933 2934
    vidattr(A_NORMAL);
    return 0;
  }
  if (skip_updates)
  {
    vidattr(A_BOLD);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2935
    tee_fprintf(stdout, "\nAll updates ignored to this database\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2936 2937
    vidattr(A_NORMAL);
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2938
#ifdef USE_POPEN
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2939
  tee_fprintf(stdout, "Current pager:\t\t%s\n", pager);
2940
  tee_fprintf(stdout, "Using outfile:\t\t'%s'\n", opt_outfile ? outfile : "");
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2941
#endif
2942
  tee_fprintf(stdout, "Using delimiter:\t%s\n", delimiter);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2943 2944 2945
  tee_fprintf(stdout, "Server version:\t\t%s\n", mysql_get_server_info(&mysql));
  tee_fprintf(stdout, "Protocol version:\t%d\n", mysql_get_proto_info(&mysql));
  tee_fprintf(stdout, "Connection:\t\t%s\n", mysql_get_host_info(&mysql));
2946 2947 2948
  if ((id= mysql_insert_id(&mysql)))
    tee_fprintf(stdout, "Insert id:\t\t%s\n", llstr(id, buff));

bar@mysql.com's avatar
bar@mysql.com committed
2949 2950 2951 2952 2953
  /* 
    Don't remove "limit 1", 
    it is protection againts SQL_SELECT_LIMIT=0
  */
  if (!mysql_query(&mysql,"select @@character_set_client, @@character_set_connection, @@character_set_server, @@character_set_database limit 1") &&
bar@mysql.com's avatar
bar@mysql.com committed
2954 2955 2956 2957 2958
      (result=mysql_use_result(&mysql)))
  {
    MYSQL_ROW cur=mysql_fetch_row(result);
    if (cur)
    {
2959
      tee_fprintf(stdout, "Server characterset:\t%s\n", cur[2] ? cur[2] : "");
bar@mysql.com's avatar
bar@mysql.com committed
2960
      tee_fprintf(stdout, "Db     characterset:\t%s\n", cur[3] ? cur[3] : "");
2961
      tee_fprintf(stdout, "Client characterset:\t%s\n", cur[0] ? cur[0] : "");
bar@mysql.com's avatar
bar@mysql.com committed
2962 2963 2964 2965
      tee_fprintf(stdout, "Conn.  characterset:\t%s\n", cur[1] ? cur[1] : "");
    }
    mysql_free_result(result);
  }
2966 2967 2968 2969 2970 2971
  else
  {
    /* Probably pre-4.1 server */
    tee_fprintf(stdout, "Client characterset:\t%s\n", charset_info->csname);
    tee_fprintf(stdout, "Server characterset:\t%s\n", mysql.charset->csname);
  }
bar@mysql.com's avatar
bar@mysql.com committed
2972

2973
#ifndef EMBEDDED_LIBRARY
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2974
  if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || ! mysql.unix_socket)
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2975
    tee_fprintf(stdout, "TCP port:\t\t%d\n", mysql.port);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2976
  else
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2977
    tee_fprintf(stdout, "UNIX socket:\t\t%s\n", mysql.unix_socket);
2978 2979
  if (mysql.net.compress)
    tee_fprintf(stdout, "Protocol:\t\tCompressed\n");
2980
#endif
2981

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2982 2983 2984
  if ((status=mysql_stat(&mysql)) && !mysql_error(&mysql)[0])
  {
    ulong sec;
2985 2986 2987 2988
    char buff[40];
    const char *pos= strchr(status,' ');
    /* print label */
    tee_fprintf(stdout, "%.*s\t\t\t", (int) (pos-status), status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2989 2990 2991
    if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec)))
    {
      nice_time((double) sec,buff,0);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2992
      tee_puts(buff, stdout);			/* print nice time */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2993 2994 2995 2996
      while (*status == ' ') status++;		/* to next info */
    }
    if (status)
    {
2997
      tee_putc('\n', stdout);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
2998
      tee_puts(status, stdout);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2999 3000 3001 3002 3003
    }
  }
  if (safe_updates)
  {
    vidattr(A_BOLD);
jcole@tetra.spaceapes.com's avatar
jcole@tetra.spaceapes.com committed
3004
    tee_fprintf(stdout, "\nNote that you are running in safe_update_mode:\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3005
    vidattr(A_NORMAL);
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
3006
    tee_fprintf(stdout, "\
jcole@tetra.spaceapes.com's avatar
jcole@tetra.spaceapes.com committed
3007 3008 3009
UPDATEs and DELETEs that don't use a key in the WHERE clause are not allowed.\n\
(One can force an UPDATE/DELETE by adding LIMIT # at the end of the command.)\n\
SELECT has an automatic 'LIMIT %lu' if LIMIT is not used.\n\
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3010
Max number of examined row combination in a join is set to: %lu\n\n",
jcole@tetra.spaceapes.com's avatar
jcole@tetra.spaceapes.com committed
3011
select_limit, max_join_size);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3012
  }
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
3013
  tee_puts("--------------\n", stdout);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3014 3015 3016 3017 3018
  return 0;
}


static int
3019
put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3020
{
3021
  FILE *file= (info_type == INFO_ERROR ? stderr : stdout);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3022
  static int inited=0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3023

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3024 3025 3026 3027
  if (status.batch)
  {
    if (info_type == INFO_ERROR)
    {
3028 3029
      (void) fflush(file);
      fprintf(file,"ERROR");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3030
      if (error)
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
3031 3032 3033 3034 3035 3036
      {
	if (sqlstate)
	  (void) fprintf(file," %d (%s)",error, sqlstate);
        else
	  (void) fprintf(file," %d",error);
      }
3037
      if (status.query_start_line && line_numbers)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3038
      {
3039
	(void) fprintf(file," at line %lu",status.query_start_line);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3040
	if (status.file_name)
3041
	  (void) fprintf(file," in file: '%s'", status.file_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3042
      }
3043 3044
      (void) fprintf(file,": %s\n",str);
      (void) fflush(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3045 3046 3047 3048
      if (!ignore_errors)
	return 1;
    }
    else if (info_type == INFO_RESULT && verbose > 1)
3049
      tee_puts(str, file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3050
    if (unbuffered)
3051
      fflush(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064
    return info_type == INFO_ERROR ? -1 : 0;
  }
  if (!opt_silent || info_type == INFO_ERROR)
  {
    if (!inited)
    {
      inited=1;
#ifdef HAVE_SETUPTERM
      (void) setupterm((char *)0, 1, (int *) 0);
#endif
    }
    if (info_type == INFO_ERROR)
    {
3065
      if (!opt_nobeep)
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3066
	putchar('\007');		      	/* This should make a bell */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3067 3068
      vidattr(A_STANDOUT);
      if (error)
3069 3070 3071 3072 3073 3074
      {
	if (sqlstate)
          (void) tee_fprintf(file, "ERROR %d (%s): ", error, sqlstate);
        else
          (void) tee_fprintf(file, "ERROR %d: ", error);
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3075
      else
3076
        tee_puts("ERROR: ", file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3077 3078 3079
    }
    else
      vidattr(A_BOLD);
3080
    (void) tee_puts(str, file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3081 3082 3083
    vidattr(A_NORMAL);
  }
  if (unbuffered)
3084
    fflush(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3085 3086 3087
  return info_type == INFO_ERROR ? -1 : 0;
}

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
3088

3089 3090 3091 3092 3093 3094 3095 3096
static int
put_error(MYSQL *mysql)
{
  return put_info(mysql_error(mysql), INFO_ERROR, mysql_errno(mysql),
		  mysql_sqlstate(mysql));
}  


bk@work.mysql.com's avatar
bk@work.mysql.com committed
3097 3098 3099 3100
static void remove_cntrl(String &buffer)
{
  char *start,*end;
  end=(start=(char*) buffer.ptr())+buffer.length();
3101
  while (start < end && !my_isgraph(charset_info,end[-1]))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3102 3103 3104 3105 3106
    end--;
  buffer.length((uint) (end-start));
}


jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
3107 3108 3109 3110
void tee_fprintf(FILE *file, const char *fmt, ...)
{
  va_list args;

monty@mysql.com's avatar
monty@mysql.com committed
3111
  NETWARE_YIELD;
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
3112
  va_start(args, fmt);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3113
  (void) vfprintf(file, fmt, args);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3114 3115 3116
#ifdef OS2
  fflush( file);
#endif
3117 3118
  va_end(args);

jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
3119
  if (opt_outfile)
3120 3121
  {
    va_start(args, fmt);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3122
    (void) vfprintf(OUTFILE, fmt, args);
3123 3124
    va_end(args);
  }
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
3125 3126 3127 3128 3129
}


void tee_fputs(const char *s, FILE *file)
{
monty@mysql.com's avatar
monty@mysql.com committed
3130
  NETWARE_YIELD;
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
3131
  fputs(s, file);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3132 3133 3134
#ifdef OS2
  fflush( file);
#endif
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
3135 3136 3137 3138 3139 3140 3141
  if (opt_outfile)
    fputs(s, OUTFILE);
}


void tee_puts(const char *s, FILE *file)
{
monty@mysql.com's avatar
monty@mysql.com committed
3142
  NETWARE_YIELD;
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
3143 3144
  fputs(s, file);
  fputs("\n", file);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3145 3146 3147
#ifdef OS2
  fflush( file);
#endif
jani@prima.mysql.com's avatar
jani@prima.mysql.com committed
3148 3149 3150 3151 3152 3153 3154
  if (opt_outfile)
  {
    fputs(s, OUTFILE);
    fputs("\n", OUTFILE);
  }
}

3155 3156 3157
void tee_putc(int c, FILE *file)
{
  putc(c, file);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3158 3159 3160
#ifdef OS2
  fflush( file);
#endif
3161 3162 3163 3164
  if (opt_outfile)
    putc(c, OUTFILE);
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3165
#if defined( __WIN__) || defined( OS2) || defined(__NETWARE__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3166 3167 3168
#include <time.h>
#else
#include <sys/times.h>
3169
#ifdef _SC_CLK_TCK				// For mit-pthreads
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3170 3171 3172
#undef CLOCKS_PER_SEC
#define CLOCKS_PER_SEC (sysconf(_SC_CLK_TCK))
#endif
3173
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3174 3175 3176

static ulong start_timer(void)
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3177
#if defined( __WIN__) || defined( OS2) || defined(__NETWARE__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192
 return clock();
#else
  struct tms tms_tmp;
  return times(&tms_tmp);
#endif
}


static void nice_time(double sec,char *buff,bool part_second)
{
  ulong tmp;
  if (sec >= 3600.0*24)
  {
    tmp=(ulong) floor(sec/(3600.0*24));
    sec-=3600.0*24*tmp;
3193
    buff=int10_to_str((long) tmp, buff, 10);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3194 3195 3196 3197 3198 3199
    buff=strmov(buff,tmp > 1 ? " days " : " day ");
  }
  if (sec >= 3600.0)
  {
    tmp=(ulong) floor(sec/3600.0);
    sec-=3600.0*tmp;
3200
    buff=int10_to_str((long) tmp, buff, 10);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3201 3202 3203 3204 3205 3206
    buff=strmov(buff,tmp > 1 ? " hours " : " hour ");
  }
  if (sec >= 60.0)
  {
    tmp=(ulong) floor(sec/60.0);
    sec-=60.0*tmp;
3207
    buff=int10_to_str((long) tmp, buff, 10);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231
    buff=strmov(buff," min ");
  }
  if (part_second)
    sprintf(buff,"%.2f sec",sec);
  else
    sprintf(buff,"%d sec",(int) sec);
}


static void end_timer(ulong start_time,char *buff)
{
  nice_time((double) (start_timer() - start_time) /
	    CLOCKS_PER_SEC,buff,1);
}


static void mysql_end_timer(ulong start_time,char *buff)
{
  buff[0]=' ';
  buff[1]='(';
  end_timer(start_time,buff+2);
  strmov(strend(buff),")");
}

3232 3233
static const char* construct_prompt()
{
3234 3235
  processed_prompt.free();			// Erase the old prompt
  time_t  lclock = time(NULL);			// Get the date struct
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3236
  struct tm *t = localtime(&lclock);
3237 3238

  /* parse thru the settings for the prompt */
3239 3240 3241
  for (char *c = current_prompt; *c ; *c++)
  {
    if (*c != PROMPT_CHAR)
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3242
	processed_prompt.append(*c);
3243 3244
    else
    {
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3245 3246
      switch (*++c) {
      case '\0':
3247
	c--;			// stop it from going beyond if ends with %
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3248 3249 3250 3251 3252
	break;
      case 'c':
	add_int_to_prompt(++prompt_counter);
	break;
      case 'v':
3253 3254 3255 3256
	if (connected)
	  processed_prompt.append(mysql_get_server_info(&mysql));
	else
	  processed_prompt.append("not_connected");
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3257 3258 3259 3260 3261 3262
	break;
      case 'd':
	processed_prompt.append(current_db ? current_db : "(none)");
	break;
      case 'h':
      {
3263 3264
	const char *prompt;
	prompt= connected ? mysql_get_host_info(&mysql) : "not_connected";
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3265 3266 3267 3268 3269 3270 3271 3272 3273 3274
	if (strstr(prompt, "Localhost"))
	  processed_prompt.append("localhost");
	else
	{
	  const char *end=strcend(prompt,' ');
	  processed_prompt.append(prompt, (uint) (end-prompt));
	}
	break;
      }
      case 'p':
3275
      {
3276
#ifndef EMBEDDED_LIBRARY
3277 3278 3279 3280 3281
	if (!connected)
	{
	  processed_prompt.append("not_connected");
	  break;
	}
3282 3283 3284 3285 3286 3287 3288

	const char *host_info = mysql_get_host_info(&mysql);
	if (strstr(host_info, "memory")) 
	{
		processed_prompt.append( mysql.host );
	}
	else if (strstr(host_info,"TCP/IP") ||
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3289
	    !mysql.unix_socket)
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3290 3291
	  add_int_to_prompt(mysql.port);
	else
3292 3293
	{
	  char *pos=strrchr(mysql.unix_socket,'/');
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3294
 	  processed_prompt.append(pos ? pos+1 : mysql.unix_socket);
3295
	}
3296
#endif
3297
      }
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319
	break;
      case 'U':
	if (!full_username)
	  init_username();
	processed_prompt.append(full_username);
	break;
      case 'u':
	if (!full_username)
	  init_username();
	processed_prompt.append(part_username);
	break;
      case PROMPT_CHAR:
	processed_prompt.append(PROMPT_CHAR);
	break;
      case 'n':
	processed_prompt.append('\n');
	break;
      case ' ':
      case '_':
	processed_prompt.append(' ');
	break;
      case 'R':
3320 3321
	if (t->tm_hour < 10)
	  processed_prompt.append('0');
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3322 3323 3324 3325 3326 3327 3328
	add_int_to_prompt(t->tm_hour);
	break;
      case 'r':
	int getHour;
	getHour = t->tm_hour % 12;
	if (getHour == 0)
	  getHour=12;
3329 3330
	if (getHour < 10)
	  processed_prompt.append('0');
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355
	add_int_to_prompt(getHour);
	break;
      case 'm':
	if (t->tm_min < 10)
	  processed_prompt.append('0');
	add_int_to_prompt(t->tm_min);
	break;
      case 'y':
	int getYear;
	getYear = t->tm_year % 100;
	if (getYear < 10)
	  processed_prompt.append('0');
	add_int_to_prompt(getYear);
	break;
      case 'Y':
	add_int_to_prompt(t->tm_year+1900);
	break;
      case 'D':
	char* dateTime;
	time_t lclock;
	lclock = time(NULL);
	dateTime = ctime(&lclock);
	processed_prompt.append(strtok(dateTime,"\n"));
	break;
      case 's':
3356 3357
	if (t->tm_sec < 10)
	  processed_prompt.append('0');
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392
	add_int_to_prompt(t->tm_sec);
	break;
      case 'w':
	processed_prompt.append(day_names[t->tm_wday]);
	break;
      case 'P':
	processed_prompt.append(t->tm_hour < 12 ? "am" : "pm");
	break;
      case 'o':
	add_int_to_prompt(t->tm_mon+1);
	break;
      case 'O':
	processed_prompt.append(month_names[t->tm_mon]);
	break;
      case '\'':
	processed_prompt.append("'");
	break;
      case '"':
	processed_prompt.append('"');
	break;
      case 'S':
	processed_prompt.append(';');
	break;
      case 't':
	processed_prompt.append('\t');
	break;
      default:
	processed_prompt.append(c);
      }
    }
  }
  processed_prompt.append('\0');
  return processed_prompt.ptr();
}

3393 3394 3395

static void add_int_to_prompt(int toadd)
{
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3396 3397 3398 3399 3400
  char buffer[16];
  int10_to_str(toadd,buffer,10);
  processed_prompt.append(buffer);
}

3401 3402
static void init_username()
{
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3403 3404 3405 3406 3407 3408 3409
  my_free(full_username,MYF(MY_ALLOW_ZERO_PTR));
  my_free(part_username,MYF(MY_ALLOW_ZERO_PTR));

  MYSQL_RES *result;
  LINT_INIT(result);
  if (!mysql_query(&mysql,"select USER()") &&
      (result=mysql_use_result(&mysql)))
3410 3411 3412 3413 3414 3415
  {
    MYSQL_ROW cur=mysql_fetch_row(result);
    full_username=my_strdup(cur[0],MYF(MY_WME));
    part_username=my_strdup(strtok(cur[0],"@"),MYF(MY_WME));
    (void) mysql_fetch_row(result);		// Read eof
  }
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3416 3417
}

3418 3419 3420
static int com_prompt(String *buffer, char *line)
{
  char *ptr=strchr(line, ' ');
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3421 3422
  prompt_counter = 0;
  my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR));
3423 3424
  current_prompt=my_strdup(ptr ? ptr+1 : default_prompt,MYF(MY_WME));
  if (!ptr)
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3425 3426 3427 3428 3429 3430
    tee_fprintf(stdout, "Returning to default PROMPT of %s\n", default_prompt);
  else
    tee_fprintf(stdout, "PROMPT set to '%s'\n", current_prompt);
  return 0;
}

3431
#ifndef EMBEDDED_LIBRARY
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442
/* Keep sql_string library happy */

gptr sql_alloc(unsigned int Size)
{
  return my_malloc(Size,MYF(MY_WME));
}

void sql_element_free(void *ptr)
{
  my_free((gptr) ptr,MYF(0));
}
3443
#endif /* EMBEDDED_LIBRARY */