MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mysql.cc
1 /*
2  Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 /* mysql command tool
19  * Commands compatible with mSQL by David J. Hughes
20  *
21  * Written by:
22  * Michael 'Monty' Widenius
23  * Andi Gutmans <andi@zend.com>
24  * Zeev Suraski <zeev@zend.com>
25  * Jani Tolonen <jani@mysql.com>
26  * Matt Wagner <matt@mysql.com>
27  * Jeremy Cole <jcole@mysql.com>
28  * Tonu Samuel <tonu@mysql.com>
29  * Harrison Fisk <harrison@mysql.com>
30  *
31  **/
32 
33 #include "client_priv.h"
34 #include "my_default.h"
35 #include <m_ctype.h>
36 #include <stdarg.h>
37 #include <my_dir.h>
38 #ifndef __GNU_LIBRARY__
39 #define __GNU_LIBRARY__ // Skip warnings in getopt.h
40 #endif
41 #include "my_readline.h"
42 #include <signal.h>
43 #include <violite.h>
44 
45 #include <algorithm>
46 
47 using std::min;
48 using std::max;
49 
50 #if defined(USE_LIBEDIT_INTERFACE) && defined(HAVE_LOCALE_H)
51 #include <locale.h>
52 #endif
53 
54 const char *VER= "14.14";
55 
56 /* Don't try to make a nice table if the data is too big */
57 #define MAX_COLUMN_LENGTH 1024
58 
59 /* Buffer to hold 'version' and 'version_comment' */
60 static char *server_version= NULL;
61 
62 /* Array of options to pass to libemysqld */
63 #define MAX_SERVER_ARGS 64
64 
65 /* Maximum memory limit that can be claimed by alloca(). */
66 #define MAX_ALLOCA_SIZE 512
67 
68 #include "sql_string.h"
69 
70 extern "C" {
71 #if defined(HAVE_CURSES_H) && defined(HAVE_TERM_H)
72 #include <curses.h>
73 #include <term.h>
74 #else
75 #if defined(HAVE_TERMIOS_H)
76 #include <termios.h>
77 #include <unistd.h>
78 #elif defined(HAVE_TERMBITS_H)
79 #include <termbits.h>
80 #elif defined(HAVE_ASM_TERMBITS_H) && (!defined __GLIBC__ || !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ > 0))
81 #include <asm/termbits.h> // Standard linux
82 #endif
83 #undef VOID
84 #if defined(HAVE_TERMCAP_H)
85 #include <termcap.h>
86 #else
87 #ifdef HAVE_CURSES_H
88 #include <curses.h>
89 #endif
90 #undef SYSV // hack to avoid syntax error
91 #ifdef HAVE_TERM_H
92 #include <term.h>
93 #endif
94 #endif
95 #endif
96 
97 #if defined(__WIN__)
98 #include <conio.h>
99 #else
100 #include <readline.h>
101 #define HAVE_READLINE
102 #define USE_POPEN
103 #endif
104  //int vidattr(long unsigned int attrs); // Was missing in sun curses
105 }
106 
107 #if !defined(HAVE_VIDATTR)
108 #undef vidattr
109 #define vidattr(A) {} // Can't get this to work
110 #endif
111 
112 #ifdef FN_NO_CASE_SENSE
113 #define cmp_database(cs,A,B) my_strcasecmp((cs), (A), (B))
114 #else
115 #define cmp_database(cs,A,B) strcmp((A),(B))
116 #endif
117 
118 #include "completion_hash.h"
119 #include <welcome_copyright_notice.h> // ORACLE_WELCOME_COPYRIGHT_NOTICE
120 
121 #define PROMPT_CHAR '\\'
122 #define DEFAULT_DELIMITER ";"
123 
124 #define MAX_BATCH_BUFFER_SIZE (1024L * 1024L * 1024L)
125 
126 typedef struct st_status
127 {
128  int exit_status;
129  ulong query_start_line;
130  char *file_name;
131  LINE_BUFFER *line_buff;
132  bool batch,add_to_history;
133 } STATUS;
134 
135 
136 static HashTable ht;
137 static char **defaults_argv;
138 
139 enum enum_info_type { INFO_INFO,INFO_ERROR,INFO_RESULT};
140 typedef enum enum_info_type INFO_TYPE;
141 
142 static MYSQL mysql; /* The connection */
143 static my_bool ignore_errors=0,wait_flag=0,quick=0,
144  connected=0,opt_raw_data=0,unbuffered=0,output_tables=0,
145  opt_rehash=1,skip_updates=0,safe_updates=0,one_database=0,
146  opt_compress=0, using_opt_local_infile=0,
147  vertical=0, line_numbers=1, column_names=1,opt_html=0,
148  opt_xml=0,opt_nopager=1, opt_outfile=0, named_cmds= 0,
149  tty_password= 0, opt_nobeep=0, opt_reconnect=1,
150  opt_secure_auth= TRUE,
151  default_pager_set= 0, opt_sigint_ignore= 0,
152  auto_vertical_output= 0,
153  show_warnings= 0, executing_query= 0, interrupted_query= 0,
154  ignore_spaces= 0;
155 static my_bool debug_info_flag, debug_check_flag;
156 static my_bool column_types_flag;
157 static my_bool preserve_comments= 0;
158 static ulong opt_max_allowed_packet, opt_net_buffer_length;
159 static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0;
160 static uint opt_enable_cleartext_plugin= 0;
161 static my_bool using_opt_enable_cleartext_plugin= 0;
162 static uint my_end_arg;
163 static char * opt_mysql_unix_port=0;
164 static char *opt_bind_addr = NULL;
165 static int connect_flag=CLIENT_INTERACTIVE;
166 static my_bool opt_binary_mode= FALSE;
167 static my_bool opt_connect_expired_password= FALSE;
168 static char *current_host,*current_db,*current_user=0,*opt_password=0,
169  *current_prompt=0, *delimiter_str= 0,
170  *default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME,
171  *opt_init_command= 0;
172 static char *histfile;
173 static char *histfile_tmp;
174 static char *opt_histignore= NULL;
175 DYNAMIC_STRING histignore_buffer;
176 static String glob_buffer,old_buffer;
177 static String processed_prompt;
178 static char *full_username=0,*part_username=0,*default_prompt=0;
179 static int wait_time = 5;
180 static STATUS status;
181 static ulong select_limit,max_join_size,opt_connect_timeout=0;
182 static char mysql_charsets_dir[FN_REFLEN+1];
183 static char *opt_plugin_dir= 0, *opt_default_auth= 0;
184 #if !defined(HAVE_YASSL)
185 static char *opt_server_public_key= 0;
186 #endif
187 static const char *xmlmeta[] = {
188  "&", "&amp;",
189  "<", "&lt;",
190  ">", "&gt;",
191  "\"", "&quot;",
192  /* Turn \0 into a space. Why not &#0;? That's not valid XML or HTML. */
193  "\0", " ",
194  0, 0
195 };
196 static const char *day_names[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
197 static const char *month_names[]={"Jan","Feb","Mar","Apr","May","Jun","Jul",
198  "Aug","Sep","Oct","Nov","Dec"};
199 static char default_pager[FN_REFLEN];
200 static char pager[FN_REFLEN], outfile[FN_REFLEN];
201 static FILE *PAGER, *OUTFILE;
202 static MEM_ROOT hash_mem_root;
203 static uint prompt_counter;
204 static char delimiter[16]= DEFAULT_DELIMITER;
205 static uint delimiter_length= 1;
206 unsigned short terminal_width= 80;
207 
208 #ifdef HAVE_SMEM
209 static char *shared_memory_base_name=0;
210 #endif
211 static uint opt_protocol=0;
212 static const CHARSET_INFO *charset_info= &my_charset_latin1;
213 
214 #include "sslopt-vars.h"
215 
216 const char *default_dbug_option="d:t:o,/tmp/mysql.trace";
217 
218 #ifdef __WIN__
219 /*
220  A flag that indicates if --execute buffer has already been converted,
221  to avoid double conversion on reconnect.
222 */
223 static my_bool execute_buffer_conversion_done= 0;
224 
225 /*
226  my_win_is_console(...) is quite slow.
227  We cache my_win_is_console() results for stdout and stderr.
228  Any other output files, except stdout and stderr,
229  cannot be Windows console.
230  Note, if mysql.exe is executed from a service, its _fileno(stdout) is -1,
231  so shift (1 << -1) can return implementation defined result.
232  This corner case is taken into account, as the shift result
233  will be multiplied to 0 and we'll get 0 as a result.
234  The same is true for stderr.
235 */
236 static uint win_is_console_cache=
237  (test(my_win_is_console(stdout)) * (1 << _fileno(stdout))) |
238  (test(my_win_is_console(stderr)) * (1 << _fileno(stderr)));
239 
240 static inline my_bool
241 my_win_is_console_cached(FILE *file)
242 {
243  return win_is_console_cache & (1 << _fileno(file));
244 }
245 #endif /* __WIN__ */
246 
247 /* Various printing flags */
248 #define MY_PRINT_ESC_0 1 /* Replace 0x00 bytes to "\0" */
249 #define MY_PRINT_SPS_0 2 /* Replace 0x00 bytes to space */
250 #define MY_PRINT_XML 4 /* Encode XML entities */
251 #define MY_PRINT_MB 8 /* Recognize multi-byte characters */
252 #define MY_PRINT_CTRL 16 /* Replace TAB, NL, CR to "\t", "\n", "\r" */
253 
254 void tee_write(FILE *file, const char *s, size_t slen, int flags);
255 void tee_fprintf(FILE *file, const char *fmt, ...);
256 void tee_fputs(const char *s, FILE *file);
257 void tee_puts(const char *s, FILE *file);
258 void tee_putc(int c, FILE *file);
259 static void tee_print_sized_data(const char *, unsigned int, unsigned int, bool);
260 /* The names of functions that actually do the manipulation. */
261 static int get_options(int argc,char **argv);
262 extern "C" my_bool get_one_option(int optid, const struct my_option *opt,
263  char *argument);
264 static int com_quit(String *str,char*),
265  com_go(String *str,char*), com_ego(String *str,char*),
266  com_print(String *str,char*),
267  com_help(String *str,char*), com_clear(String *str,char*),
268  com_connect(String *str,char*), com_status(String *str,char*),
269  com_use(String *str,char*), com_source(String *str, char*),
270  com_rehash(String *str, char*), com_tee(String *str, char*),
271  com_notee(String *str, char*), com_charset(String *str,char*),
272  com_prompt(String *str, char*), com_delimiter(String *str, char*),
273  com_warnings(String *str, char*), com_nowarnings(String *str, char*);
274 
275 #ifdef USE_POPEN
276 static int com_nopager(String *str, char*), com_pager(String *str, char*),
277  com_edit(String *str,char*), com_shell(String *str, char *);
278 #endif
279 
280 static int read_and_execute(bool interactive);
281 static int sql_connect(char *host,char *database,char *user,char *password,
282  uint silent);
283 static const char *server_version_string(MYSQL *mysql);
284 static int put_info(const char *str,INFO_TYPE info,uint error=0,
285  const char *sql_state=0);
286 static int put_error(MYSQL *mysql);
287 static void safe_put_field(const char *pos,ulong length);
288 static void xmlencode_print(const char *src, uint length);
289 static void init_pager();
290 static void end_pager();
291 static void init_tee(const char *);
292 static void end_tee();
293 static const char* construct_prompt();
294 static char *get_arg(char *line, my_bool get_next_arg);
295 static void init_username();
296 static void add_int_to_prompt(int toadd);
297 static int get_result_width(MYSQL_RES *res);
298 static int get_field_disp_length(MYSQL_FIELD * field);
299 static int normalize_dbname(const char *line, char *buff, uint buff_size);
300 static int get_quote_count(const char *line);
301 
302 #if defined(HAVE_READLINE)
303 static void add_filtered_history(const char *string);
304 static my_bool check_histignore(const char *string);
305 static my_bool parse_histignore();
306 static my_bool init_hist_patterns();
307 static void free_hist_patterns();
308 DYNAMIC_ARRAY histignore_patterns;
309 #endif /* HAVE_READLINE */
310 
311 /* A structure which contains information on the commands this program
312  can understand. */
313 
314 typedef struct {
315  const char *name; /* User printable name of the function. */
316  char cmd_char; /* msql command character */
317  int (*func)(String *str,char *); /* Function to call to do the job. */
318  bool takes_params; /* Max parameters for command */
319  const char *doc; /* Documentation for this function. */
320 } COMMANDS;
321 
322 static COMMANDS commands[] = {
323  { "?", '?', com_help, 1, "Synonym for `help'." },
324  { "clear", 'c', com_clear, 0, "Clear the current input statement."},
325  { "connect",'r', com_connect,1,
326  "Reconnect to the server. Optional arguments are db and host." },
327  { "delimiter", 'd', com_delimiter, 1,
328  "Set statement delimiter." },
329 #ifdef USE_POPEN
330  { "edit", 'e', com_edit, 0, "Edit command with $EDITOR."},
331 #endif
332  { "ego", 'G', com_ego, 0,
333  "Send command to mysql server, display result vertically."},
334  { "exit", 'q', com_quit, 0, "Exit mysql. Same as quit."},
335  { "go", 'g', com_go, 0, "Send command to mysql server." },
336  { "help", 'h', com_help, 1, "Display this help." },
337 #ifdef USE_POPEN
338  { "nopager",'n', com_nopager,0, "Disable pager, print to stdout." },
339 #endif
340  { "notee", 't', com_notee, 0, "Don't write into outfile." },
341 #ifdef USE_POPEN
342  { "pager", 'P', com_pager, 1,
343  "Set PAGER [to_pager]. Print the query results via PAGER." },
344 #endif
345  { "print", 'p', com_print, 0, "Print current command." },
346  { "prompt", 'R', com_prompt, 1, "Change your mysql prompt."},
347  { "quit", 'q', com_quit, 0, "Quit mysql." },
348  { "rehash", '#', com_rehash, 0, "Rebuild completion hash." },
349  { "source", '.', com_source, 1,
350  "Execute an SQL script file. Takes a file name as an argument."},
351  { "status", 's', com_status, 0, "Get status information from the server."},
352 #ifdef USE_POPEN
353  { "system", '!', com_shell, 1, "Execute a system shell command."},
354 #endif
355  { "tee", 'T', com_tee, 1,
356  "Set outfile [to_outfile]. Append everything into given outfile." },
357  { "use", 'u', com_use, 1,
358  "Use another database. Takes database name as argument." },
359  { "charset", 'C', com_charset, 1,
360  "Switch to another charset. Might be needed for processing binlog with multi-byte charsets." },
361  { "warnings", 'W', com_warnings, 0,
362  "Show warnings after every statement." },
363  { "nowarning", 'w', com_nowarnings, 0,
364  "Don't show warnings after every statement." },
365  /* Get bash-like expansion for some commands */
366  { "create table", 0, 0, 0, ""},
367  { "create database", 0, 0, 0, ""},
368  { "show databases", 0, 0, 0, ""},
369  { "show fields from", 0, 0, 0, ""},
370  { "show keys from", 0, 0, 0, ""},
371  { "show tables", 0, 0, 0, ""},
372  { "load data from", 0, 0, 0, ""},
373  { "alter table", 0, 0, 0, ""},
374  { "set option", 0, 0, 0, ""},
375  { "lock tables", 0, 0, 0, ""},
376  { "unlock tables", 0, 0, 0, ""},
377  /* generated 2006-12-28. Refresh occasionally from lexer. */
378  { "ACTION", 0, 0, 0, ""},
379  { "ADD", 0, 0, 0, ""},
380  { "AFTER", 0, 0, 0, ""},
381  { "AGAINST", 0, 0, 0, ""},
382  { "AGGREGATE", 0, 0, 0, ""},
383  { "ALL", 0, 0, 0, ""},
384  { "ALGORITHM", 0, 0, 0, ""},
385  { "ALTER", 0, 0, 0, ""},
386  { "ANALYZE", 0, 0, 0, ""},
387  { "AND", 0, 0, 0, ""},
388  { "ANY", 0, 0, 0, ""},
389  { "AS", 0, 0, 0, ""},
390  { "ASC", 0, 0, 0, ""},
391  { "ASCII", 0, 0, 0, ""},
392  { "ASENSITIVE", 0, 0, 0, ""},
393  { "AUTO_INCREMENT", 0, 0, 0, ""},
394  { "AVG", 0, 0, 0, ""},
395  { "AVG_ROW_LENGTH", 0, 0, 0, ""},
396  { "BACKUP", 0, 0, 0, ""},
397  { "BDB", 0, 0, 0, ""},
398  { "BEFORE", 0, 0, 0, ""},
399  { "BEGIN", 0, 0, 0, ""},
400  { "BERKELEYDB", 0, 0, 0, ""},
401  { "BETWEEN", 0, 0, 0, ""},
402  { "BIGINT", 0, 0, 0, ""},
403  { "BINARY", 0, 0, 0, ""},
404  { "BINLOG", 0, 0, 0, ""},
405  { "BIT", 0, 0, 0, ""},
406  { "BLOB", 0, 0, 0, ""},
407  { "BOOL", 0, 0, 0, ""},
408  { "BOOLEAN", 0, 0, 0, ""},
409  { "BOTH", 0, 0, 0, ""},
410  { "BTREE", 0, 0, 0, ""},
411  { "BY", 0, 0, 0, ""},
412  { "BYTE", 0, 0, 0, ""},
413  { "CACHE", 0, 0, 0, ""},
414  { "CALL", 0, 0, 0, ""},
415  { "CASCADE", 0, 0, 0, ""},
416  { "CASCADED", 0, 0, 0, ""},
417  { "CASE", 0, 0, 0, ""},
418  { "CHAIN", 0, 0, 0, ""},
419  { "CHANGE", 0, 0, 0, ""},
420  { "CHANGED", 0, 0, 0, ""},
421  { "CHAR", 0, 0, 0, ""},
422  { "CHARACTER", 0, 0, 0, ""},
423  { "CHARSET", 0, 0, 0, ""},
424  { "CHECK", 0, 0, 0, ""},
425  { "CHECKSUM", 0, 0, 0, ""},
426  { "CIPHER", 0, 0, 0, ""},
427  { "CLIENT", 0, 0, 0, ""},
428  { "CLOSE", 0, 0, 0, ""},
429  { "CODE", 0, 0, 0, ""},
430  { "COLLATE", 0, 0, 0, ""},
431  { "COLLATION", 0, 0, 0, ""},
432  { "COLUMN", 0, 0, 0, ""},
433  { "COLUMNS", 0, 0, 0, ""},
434  { "COMMENT", 0, 0, 0, ""},
435  { "COMMIT", 0, 0, 0, ""},
436  { "COMMITTED", 0, 0, 0, ""},
437  { "COMPACT", 0, 0, 0, ""},
438  { "COMPRESSED", 0, 0, 0, ""},
439  { "CONCURRENT", 0, 0, 0, ""},
440  { "CONDITION", 0, 0, 0, ""},
441  { "CONNECTION", 0, 0, 0, ""},
442  { "CONSISTENT", 0, 0, 0, ""},
443  { "CONSTRAINT", 0, 0, 0, ""},
444  { "CONTAINS", 0, 0, 0, ""},
445  { "CONTINUE", 0, 0, 0, ""},
446  { "CONVERT", 0, 0, 0, ""},
447  { "CREATE", 0, 0, 0, ""},
448  { "CROSS", 0, 0, 0, ""},
449  { "CUBE", 0, 0, 0, ""},
450  { "CURRENT_DATE", 0, 0, 0, ""},
451  { "CURRENT_TIME", 0, 0, 0, ""},
452  { "CURRENT_TIMESTAMP", 0, 0, 0, ""},
453  { "CURRENT_USER", 0, 0, 0, ""},
454  { "CURSOR", 0, 0, 0, ""},
455  { "DATA", 0, 0, 0, ""},
456  { "DATABASE", 0, 0, 0, ""},
457  { "DATABASES", 0, 0, 0, ""},
458  { "DATE", 0, 0, 0, ""},
459  { "DATETIME", 0, 0, 0, ""},
460  { "DAY", 0, 0, 0, ""},
461  { "DAY_HOUR", 0, 0, 0, ""},
462  { "DAY_MICROSECOND", 0, 0, 0, ""},
463  { "DAY_MINUTE", 0, 0, 0, ""},
464  { "DAY_SECOND", 0, 0, 0, ""},
465  { "DEALLOCATE", 0, 0, 0, ""},
466  { "DEC", 0, 0, 0, ""},
467  { "DECIMAL", 0, 0, 0, ""},
468  { "DECLARE", 0, 0, 0, ""},
469  { "DEFAULT", 0, 0, 0, ""},
470  { "DEFINER", 0, 0, 0, ""},
471  { "DELAYED", 0, 0, 0, ""},
472  { "DELAY_KEY_WRITE", 0, 0, 0, ""},
473  { "DELETE", 0, 0, 0, ""},
474  { "DESC", 0, 0, 0, ""},
475  { "DESCRIBE", 0, 0, 0, ""},
476  { "DES_KEY_FILE", 0, 0, 0, ""},
477  { "DETERMINISTIC", 0, 0, 0, ""},
478  { "DIRECTORY", 0, 0, 0, ""},
479  { "DISABLE", 0, 0, 0, ""},
480  { "DISCARD", 0, 0, 0, ""},
481  { "DISTINCT", 0, 0, 0, ""},
482  { "DISTINCTROW", 0, 0, 0, ""},
483  { "DIV", 0, 0, 0, ""},
484  { "DO", 0, 0, 0, ""},
485  { "DOUBLE", 0, 0, 0, ""},
486  { "DROP", 0, 0, 0, ""},
487  { "DUAL", 0, 0, 0, ""},
488  { "DUMPFILE", 0, 0, 0, ""},
489  { "DUPLICATE", 0, 0, 0, ""},
490  { "DYNAMIC", 0, 0, 0, ""},
491  { "EACH", 0, 0, 0, ""},
492  { "ELSE", 0, 0, 0, ""},
493  { "ELSEIF", 0, 0, 0, ""},
494  { "ENABLE", 0, 0, 0, ""},
495  { "ENCLOSED", 0, 0, 0, ""},
496  { "END", 0, 0, 0, ""},
497  { "ENGINE", 0, 0, 0, ""},
498  { "ENGINES", 0, 0, 0, ""},
499  { "ENUM", 0, 0, 0, ""},
500  { "ERRORS", 0, 0, 0, ""},
501  { "ESCAPE", 0, 0, 0, ""},
502  { "ESCAPED", 0, 0, 0, ""},
503  { "EVENTS", 0, 0, 0, ""},
504  { "EXECUTE", 0, 0, 0, ""},
505  { "EXISTS", 0, 0, 0, ""},
506  { "EXIT", 0, 0, 0, ""},
507  { "EXPANSION", 0, 0, 0, ""},
508  { "EXPLAIN", 0, 0, 0, ""},
509  { "EXTENDED", 0, 0, 0, ""},
510  { "FALSE", 0, 0, 0, ""},
511  { "FAST", 0, 0, 0, ""},
512  { "FETCH", 0, 0, 0, ""},
513  { "FIELDS", 0, 0, 0, ""},
514  { "FILE", 0, 0, 0, ""},
515  { "FIRST", 0, 0, 0, ""},
516  { "FIXED", 0, 0, 0, ""},
517  { "FLOAT", 0, 0, 0, ""},
518  { "FLOAT4", 0, 0, 0, ""},
519  { "FLOAT8", 0, 0, 0, ""},
520  { "FLUSH", 0, 0, 0, ""},
521  { "FOR", 0, 0, 0, ""},
522  { "FORCE", 0, 0, 0, ""},
523  { "FOREIGN", 0, 0, 0, ""},
524  { "FOUND", 0, 0, 0, ""},
525  { "FROM", 0, 0, 0, ""},
526  { "FULL", 0, 0, 0, ""},
527  { "FULLTEXT", 0, 0, 0, ""},
528  { "FUNCTION", 0, 0, 0, ""},
529  { "GEOMETRY", 0, 0, 0, ""},
530  { "GEOMETRYCOLLECTION", 0, 0, 0, ""},
531  { "GET_FORMAT", 0, 0, 0, ""},
532  { "GLOBAL", 0, 0, 0, ""},
533  { "GRANT", 0, 0, 0, ""},
534  { "GRANTS", 0, 0, 0, ""},
535  { "GROUP", 0, 0, 0, ""},
536  { "HANDLER", 0, 0, 0, ""},
537  { "HASH", 0, 0, 0, ""},
538  { "HAVING", 0, 0, 0, ""},
539  { "HELP", 0, 0, 0, ""},
540  { "HIGH_PRIORITY", 0, 0, 0, ""},
541  { "HOSTS", 0, 0, 0, ""},
542  { "HOUR", 0, 0, 0, ""},
543  { "HOUR_MICROSECOND", 0, 0, 0, ""},
544  { "HOUR_MINUTE", 0, 0, 0, ""},
545  { "HOUR_SECOND", 0, 0, 0, ""},
546  { "IDENTIFIED", 0, 0, 0, ""},
547  { "IF", 0, 0, 0, ""},
548  { "IGNORE", 0, 0, 0, ""},
549  { "IMPORT", 0, 0, 0, ""},
550  { "IN", 0, 0, 0, ""},
551  { "INDEX", 0, 0, 0, ""},
552  { "INDEXES", 0, 0, 0, ""},
553  { "INFILE", 0, 0, 0, ""},
554  { "INNER", 0, 0, 0, ""},
555  { "INNOBASE", 0, 0, 0, ""},
556  { "INNODB", 0, 0, 0, ""},
557  { "INOUT", 0, 0, 0, ""},
558  { "INSENSITIVE", 0, 0, 0, ""},
559  { "INSERT", 0, 0, 0, ""},
560  { "INSERT_METHOD", 0, 0, 0, ""},
561  { "INT", 0, 0, 0, ""},
562  { "INT1", 0, 0, 0, ""},
563  { "INT2", 0, 0, 0, ""},
564  { "INT3", 0, 0, 0, ""},
565  { "INT4", 0, 0, 0, ""},
566  { "INT8", 0, 0, 0, ""},
567  { "INTEGER", 0, 0, 0, ""},
568  { "INTERVAL", 0, 0, 0, ""},
569  { "INTO", 0, 0, 0, ""},
570  { "IO_THREAD", 0, 0, 0, ""},
571  { "IS", 0, 0, 0, ""},
572  { "ISOLATION", 0, 0, 0, ""},
573  { "ISSUER", 0, 0, 0, ""},
574  { "ITERATE", 0, 0, 0, ""},
575  { "INVOKER", 0, 0, 0, ""},
576  { "JOIN", 0, 0, 0, ""},
577  { "KEY", 0, 0, 0, ""},
578  { "KEYS", 0, 0, 0, ""},
579  { "KILL", 0, 0, 0, ""},
580  { "LANGUAGE", 0, 0, 0, ""},
581  { "LAST", 0, 0, 0, ""},
582  { "LEADING", 0, 0, 0, ""},
583  { "LEAVE", 0, 0, 0, ""},
584  { "LEAVES", 0, 0, 0, ""},
585  { "LEFT", 0, 0, 0, ""},
586  { "LEVEL", 0, 0, 0, ""},
587  { "LIKE", 0, 0, 0, ""},
588  { "LIMIT", 0, 0, 0, ""},
589  { "LINES", 0, 0, 0, ""},
590  { "LINESTRING", 0, 0, 0, ""},
591  { "LOAD", 0, 0, 0, ""},
592  { "LOCAL", 0, 0, 0, ""},
593  { "LOCALTIME", 0, 0, 0, ""},
594  { "LOCALTIMESTAMP", 0, 0, 0, ""},
595  { "LOCK", 0, 0, 0, ""},
596  { "LOCKS", 0, 0, 0, ""},
597  { "LOGS", 0, 0, 0, ""},
598  { "LONG", 0, 0, 0, ""},
599  { "LONGBLOB", 0, 0, 0, ""},
600  { "LONGTEXT", 0, 0, 0, ""},
601  { "LOOP", 0, 0, 0, ""},
602  { "LOW_PRIORITY", 0, 0, 0, ""},
603  { "MASTER", 0, 0, 0, ""},
604  { "MASTER_CONNECT_RETRY", 0, 0, 0, ""},
605  { "MASTER_HOST", 0, 0, 0, ""},
606  { "MASTER_LOG_FILE", 0, 0, 0, ""},
607  { "MASTER_LOG_POS", 0, 0, 0, ""},
608  { "MASTER_PASSWORD", 0, 0, 0, ""},
609  { "MASTER_PORT", 0, 0, 0, ""},
610  { "MASTER_SERVER_ID", 0, 0, 0, ""},
611  { "MASTER_SSL", 0, 0, 0, ""},
612  { "MASTER_SSL_CA", 0, 0, 0, ""},
613  { "MASTER_SSL_CAPATH", 0, 0, 0, ""},
614  { "MASTER_SSL_CERT", 0, 0, 0, ""},
615  { "MASTER_SSL_CIPHER", 0, 0, 0, ""},
616  { "MASTER_SSL_KEY", 0, 0, 0, ""},
617  { "MASTER_USER", 0, 0, 0, ""},
618  { "MATCH", 0, 0, 0, ""},
619  { "MAX_CONNECTIONS_PER_HOUR", 0, 0, 0, ""},
620  { "MAX_QUERIES_PER_HOUR", 0, 0, 0, ""},
621  { "MAX_ROWS", 0, 0, 0, ""},
622  { "MAX_UPDATES_PER_HOUR", 0, 0, 0, ""},
623  { "MAX_USER_CONNECTIONS", 0, 0, 0, ""},
624  { "MEDIUM", 0, 0, 0, ""},
625  { "MEDIUMBLOB", 0, 0, 0, ""},
626  { "MEDIUMINT", 0, 0, 0, ""},
627  { "MEDIUMTEXT", 0, 0, 0, ""},
628  { "MERGE", 0, 0, 0, ""},
629  { "MICROSECOND", 0, 0, 0, ""},
630  { "MIDDLEINT", 0, 0, 0, ""},
631  { "MIGRATE", 0, 0, 0, ""},
632  { "MINUTE", 0, 0, 0, ""},
633  { "MINUTE_MICROSECOND", 0, 0, 0, ""},
634  { "MINUTE_SECOND", 0, 0, 0, ""},
635  { "MIN_ROWS", 0, 0, 0, ""},
636  { "MOD", 0, 0, 0, ""},
637  { "MODE", 0, 0, 0, ""},
638  { "MODIFIES", 0, 0, 0, ""},
639  { "MODIFY", 0, 0, 0, ""},
640  { "MONTH", 0, 0, 0, ""},
641  { "MULTILINESTRING", 0, 0, 0, ""},
642  { "MULTIPOINT", 0, 0, 0, ""},
643  { "MULTIPOLYGON", 0, 0, 0, ""},
644  { "MUTEX", 0, 0, 0, ""},
645  { "NAME", 0, 0, 0, ""},
646  { "NAMES", 0, 0, 0, ""},
647  { "NATIONAL", 0, 0, 0, ""},
648  { "NATURAL", 0, 0, 0, ""},
649  { "NDB", 0, 0, 0, ""},
650  { "NDBCLUSTER", 0, 0, 0, ""},
651  { "NCHAR", 0, 0, 0, ""},
652  { "NEW", 0, 0, 0, ""},
653  { "NEXT", 0, 0, 0, ""},
654  { "NO", 0, 0, 0, ""},
655  { "NONE", 0, 0, 0, ""},
656  { "NOT", 0, 0, 0, ""},
657  { "NO_WRITE_TO_BINLOG", 0, 0, 0, ""},
658  { "NULL", 0, 0, 0, ""},
659  { "NUMERIC", 0, 0, 0, ""},
660  { "NVARCHAR", 0, 0, 0, ""},
661  { "OFFSET", 0, 0, 0, ""},
662  { "OLD_PASSWORD", 0, 0, 0, ""},
663  { "ON", 0, 0, 0, ""},
664  { "ONE", 0, 0, 0, ""},
665  { "ONE_SHOT", 0, 0, 0, ""},
666  { "OPEN", 0, 0, 0, ""},
667  { "OPTIMIZE", 0, 0, 0, ""},
668  { "OPTION", 0, 0, 0, ""},
669  { "OPTIONALLY", 0, 0, 0, ""},
670  { "OR", 0, 0, 0, ""},
671  { "ORDER", 0, 0, 0, ""},
672  { "OUT", 0, 0, 0, ""},
673  { "OUTER", 0, 0, 0, ""},
674  { "OUTFILE", 0, 0, 0, ""},
675  { "PACK_KEYS", 0, 0, 0, ""},
676  { "PARTIAL", 0, 0, 0, ""},
677  { "PASSWORD", 0, 0, 0, ""},
678  { "PHASE", 0, 0, 0, ""},
679  { "POINT", 0, 0, 0, ""},
680  { "POLYGON", 0, 0, 0, ""},
681  { "PRECISION", 0, 0, 0, ""},
682  { "PREPARE", 0, 0, 0, ""},
683  { "PREV", 0, 0, 0, ""},
684  { "PRIMARY", 0, 0, 0, ""},
685  { "PRIVILEGES", 0, 0, 0, ""},
686  { "PROCEDURE", 0, 0, 0, ""},
687  { "PROCESS", 0, 0, 0, ""},
688  { "PROCESSLIST", 0, 0, 0, ""},
689  { "PURGE", 0, 0, 0, ""},
690  { "QUARTER", 0, 0, 0, ""},
691  { "QUERY", 0, 0, 0, ""},
692  { "QUICK", 0, 0, 0, ""},
693  { "READ", 0, 0, 0, ""},
694  { "READS", 0, 0, 0, ""},
695  { "REAL", 0, 0, 0, ""},
696  { "RECOVER", 0, 0, 0, ""},
697  { "REDUNDANT", 0, 0, 0, ""},
698  { "REFERENCES", 0, 0, 0, ""},
699  { "REGEXP", 0, 0, 0, ""},
700  { "RELAY_LOG_FILE", 0, 0, 0, ""},
701  { "RELAY_LOG_POS", 0, 0, 0, ""},
702  { "RELAY_THREAD", 0, 0, 0, ""},
703  { "RELEASE", 0, 0, 0, ""},
704  { "RELOAD", 0, 0, 0, ""},
705  { "RENAME", 0, 0, 0, ""},
706  { "REPAIR", 0, 0, 0, ""},
707  { "REPEATABLE", 0, 0, 0, ""},
708  { "REPLACE", 0, 0, 0, ""},
709  { "REPLICATION", 0, 0, 0, ""},
710  { "REPEAT", 0, 0, 0, ""},
711  { "REQUIRE", 0, 0, 0, ""},
712  { "RESET", 0, 0, 0, ""},
713  { "RESTORE", 0, 0, 0, ""},
714  { "RESTRICT", 0, 0, 0, ""},
715  { "RESUME", 0, 0, 0, ""},
716  { "RETURN", 0, 0, 0, ""},
717  { "RETURNS", 0, 0, 0, ""},
718  { "REVOKE", 0, 0, 0, ""},
719  { "RIGHT", 0, 0, 0, ""},
720  { "RLIKE", 0, 0, 0, ""},
721  { "ROLLBACK", 0, 0, 0, ""},
722  { "ROLLUP", 0, 0, 0, ""},
723  { "ROUTINE", 0, 0, 0, ""},
724  { "ROW", 0, 0, 0, ""},
725  { "ROWS", 0, 0, 0, ""},
726  { "ROW_FORMAT", 0, 0, 0, ""},
727  { "RTREE", 0, 0, 0, ""},
728  { "SAVEPOINT", 0, 0, 0, ""},
729  { "SCHEMA", 0, 0, 0, ""},
730  { "SCHEMAS", 0, 0, 0, ""},
731  { "SECOND", 0, 0, 0, ""},
732  { "SECOND_MICROSECOND", 0, 0, 0, ""},
733  { "SECURITY", 0, 0, 0, ""},
734  { "SELECT", 0, 0, 0, ""},
735  { "SENSITIVE", 0, 0, 0, ""},
736  { "SEPARATOR", 0, 0, 0, ""},
737  { "SERIAL", 0, 0, 0, ""},
738  { "SERIALIZABLE", 0, 0, 0, ""},
739  { "SESSION", 0, 0, 0, ""},
740  { "SET", 0, 0, 0, ""},
741  { "SHARE", 0, 0, 0, ""},
742  { "SHOW", 0, 0, 0, ""},
743  { "SHUTDOWN", 0, 0, 0, ""},
744  { "SIGNED", 0, 0, 0, ""},
745  { "SIMPLE", 0, 0, 0, ""},
746  { "SLAVE", 0, 0, 0, ""},
747  { "SNAPSHOT", 0, 0, 0, ""},
748  { "SMALLINT", 0, 0, 0, ""},
749  { "SOME", 0, 0, 0, ""},
750  { "SONAME", 0, 0, 0, ""},
751  { "SOUNDS", 0, 0, 0, ""},
752  { "SPATIAL", 0, 0, 0, ""},
753  { "SPECIFIC", 0, 0, 0, ""},
754  { "SQL", 0, 0, 0, ""},
755  { "SQLEXCEPTION", 0, 0, 0, ""},
756  { "SQLSTATE", 0, 0, 0, ""},
757  { "SQLWARNING", 0, 0, 0, ""},
758  { "SQL_BIG_RESULT", 0, 0, 0, ""},
759  { "SQL_BUFFER_RESULT", 0, 0, 0, ""},
760  { "SQL_CACHE", 0, 0, 0, ""},
761  { "SQL_CALC_FOUND_ROWS", 0, 0, 0, ""},
762  { "SQL_NO_CACHE", 0, 0, 0, ""},
763  { "SQL_SMALL_RESULT", 0, 0, 0, ""},
764  { "SQL_THREAD", 0, 0, 0, ""},
765  { "SQL_TSI_SECOND", 0, 0, 0, ""},
766  { "SQL_TSI_MINUTE", 0, 0, 0, ""},
767  { "SQL_TSI_HOUR", 0, 0, 0, ""},
768  { "SQL_TSI_DAY", 0, 0, 0, ""},
769  { "SQL_TSI_WEEK", 0, 0, 0, ""},
770  { "SQL_TSI_MONTH", 0, 0, 0, ""},
771  { "SQL_TSI_QUARTER", 0, 0, 0, ""},
772  { "SQL_TSI_YEAR", 0, 0, 0, ""},
773  { "SSL", 0, 0, 0, ""},
774  { "START", 0, 0, 0, ""},
775  { "STARTING", 0, 0, 0, ""},
776  { "STATUS", 0, 0, 0, ""},
777  { "STOP", 0, 0, 0, ""},
778  { "STORAGE", 0, 0, 0, ""},
779  { "STRAIGHT_JOIN", 0, 0, 0, ""},
780  { "STRING", 0, 0, 0, ""},
781  { "STRIPED", 0, 0, 0, ""},
782  { "SUBJECT", 0, 0, 0, ""},
783  { "SUPER", 0, 0, 0, ""},
784  { "SUSPEND", 0, 0, 0, ""},
785  { "TABLE", 0, 0, 0, ""},
786  { "TABLES", 0, 0, 0, ""},
787  { "TABLESPACE", 0, 0, 0, ""},
788  { "TEMPORARY", 0, 0, 0, ""},
789  { "TEMPTABLE", 0, 0, 0, ""},
790  { "TERMINATED", 0, 0, 0, ""},
791  { "TEXT", 0, 0, 0, ""},
792  { "THEN", 0, 0, 0, ""},
793  { "TIME", 0, 0, 0, ""},
794  { "TIMESTAMP", 0, 0, 0, ""},
795  { "TIMESTAMPADD", 0, 0, 0, ""},
796  { "TIMESTAMPDIFF", 0, 0, 0, ""},
797  { "TINYBLOB", 0, 0, 0, ""},
798  { "TINYINT", 0, 0, 0, ""},
799  { "TINYTEXT", 0, 0, 0, ""},
800  { "TO", 0, 0, 0, ""},
801  { "TRAILING", 0, 0, 0, ""},
802  { "TRANSACTION", 0, 0, 0, ""},
803  { "TRIGGER", 0, 0, 0, ""},
804  { "TRIGGERS", 0, 0, 0, ""},
805  { "TRUE", 0, 0, 0, ""},
806  { "TRUNCATE", 0, 0, 0, ""},
807  { "TYPE", 0, 0, 0, ""},
808  { "TYPES", 0, 0, 0, ""},
809  { "UNCOMMITTED", 0, 0, 0, ""},
810  { "UNDEFINED", 0, 0, 0, ""},
811  { "UNDO", 0, 0, 0, ""},
812  { "UNICODE", 0, 0, 0, ""},
813  { "UNION", 0, 0, 0, ""},
814  { "UNIQUE", 0, 0, 0, ""},
815  { "UNKNOWN", 0, 0, 0, ""},
816  { "UNLOCK", 0, 0, 0, ""},
817  { "UNSIGNED", 0, 0, 0, ""},
818  { "UNTIL", 0, 0, 0, ""},
819  { "UPDATE", 0, 0, 0, ""},
820  { "UPGRADE", 0, 0, 0, ""},
821  { "USAGE", 0, 0, 0, ""},
822  { "USE", 0, 0, 0, ""},
823  { "USER", 0, 0, 0, ""},
824  { "USER_RESOURCES", 0, 0, 0, ""},
825  { "USE_FRM", 0, 0, 0, ""},
826  { "USING", 0, 0, 0, ""},
827  { "UTC_DATE", 0, 0, 0, ""},
828  { "UTC_TIME", 0, 0, 0, ""},
829  { "UTC_TIMESTAMP", 0, 0, 0, ""},
830  { "VALUE", 0, 0, 0, ""},
831  { "VALUES", 0, 0, 0, ""},
832  { "VARBINARY", 0, 0, 0, ""},
833  { "VARCHAR", 0, 0, 0, ""},
834  { "VARCHARACTER", 0, 0, 0, ""},
835  { "VARIABLES", 0, 0, 0, ""},
836  { "VARYING", 0, 0, 0, ""},
837  { "WARNINGS", 0, 0, 0, ""},
838  { "WEEK", 0, 0, 0, ""},
839  { "WHEN", 0, 0, 0, ""},
840  { "WHERE", 0, 0, 0, ""},
841  { "WHILE", 0, 0, 0, ""},
842  { "VIEW", 0, 0, 0, ""},
843  { "WITH", 0, 0, 0, ""},
844  { "WORK", 0, 0, 0, ""},
845  { "WRITE", 0, 0, 0, ""},
846  { "X509", 0, 0, 0, ""},
847  { "XOR", 0, 0, 0, ""},
848  { "XA", 0, 0, 0, ""},
849  { "YEAR", 0, 0, 0, ""},
850  { "YEAR_MONTH", 0, 0, 0, ""},
851  { "ZEROFILL", 0, 0, 0, ""},
852  { "ABS", 0, 0, 0, ""},
853  { "ACOS", 0, 0, 0, ""},
854  { "ADDDATE", 0, 0, 0, ""},
855  { "ADDTIME", 0, 0, 0, ""},
856  { "AES_ENCRYPT", 0, 0, 0, ""},
857  { "AES_DECRYPT", 0, 0, 0, ""},
858  { "AREA", 0, 0, 0, ""},
859  { "ASIN", 0, 0, 0, ""},
860  { "ASBINARY", 0, 0, 0, ""},
861  { "ASTEXT", 0, 0, 0, ""},
862  { "ASWKB", 0, 0, 0, ""},
863  { "ASWKT", 0, 0, 0, ""},
864  { "ATAN", 0, 0, 0, ""},
865  { "ATAN2", 0, 0, 0, ""},
866  { "BENCHMARK", 0, 0, 0, ""},
867  { "BIN", 0, 0, 0, ""},
868  { "BIT_COUNT", 0, 0, 0, ""},
869  { "BIT_OR", 0, 0, 0, ""},
870  { "BIT_AND", 0, 0, 0, ""},
871  { "BIT_XOR", 0, 0, 0, ""},
872  { "CAST", 0, 0, 0, ""},
873  { "CEIL", 0, 0, 0, ""},
874  { "CEILING", 0, 0, 0, ""},
875  { "BIT_LENGTH", 0, 0, 0, ""},
876  { "CENTROID", 0, 0, 0, ""},
877  { "CHAR_LENGTH", 0, 0, 0, ""},
878  { "CHARACTER_LENGTH", 0, 0, 0, ""},
879  { "COALESCE", 0, 0, 0, ""},
880  { "COERCIBILITY", 0, 0, 0, ""},
881  { "COMPRESS", 0, 0, 0, ""},
882  { "CONCAT", 0, 0, 0, ""},
883  { "CONCAT_WS", 0, 0, 0, ""},
884  { "CONNECTION_ID", 0, 0, 0, ""},
885  { "CONV", 0, 0, 0, ""},
886  { "CONVERT_TZ", 0, 0, 0, ""},
887  { "COUNT", 0, 0, 0, ""},
888  { "COS", 0, 0, 0, ""},
889  { "COT", 0, 0, 0, ""},
890  { "CRC32", 0, 0, 0, ""},
891  { "CROSSES", 0, 0, 0, ""},
892  { "CURDATE", 0, 0, 0, ""},
893  { "CURTIME", 0, 0, 0, ""},
894  { "DATE_ADD", 0, 0, 0, ""},
895  { "DATEDIFF", 0, 0, 0, ""},
896  { "DATE_FORMAT", 0, 0, 0, ""},
897  { "DATE_SUB", 0, 0, 0, ""},
898  { "DAYNAME", 0, 0, 0, ""},
899  { "DAYOFMONTH", 0, 0, 0, ""},
900  { "DAYOFWEEK", 0, 0, 0, ""},
901  { "DAYOFYEAR", 0, 0, 0, ""},
902  { "DECODE", 0, 0, 0, ""},
903  { "DEGREES", 0, 0, 0, ""},
904  { "DES_ENCRYPT", 0, 0, 0, ""},
905  { "DES_DECRYPT", 0, 0, 0, ""},
906  { "DIMENSION", 0, 0, 0, ""},
907  { "DISJOINT", 0, 0, 0, ""},
908  { "ELT", 0, 0, 0, ""},
909  { "ENCODE", 0, 0, 0, ""},
910  { "ENCRYPT", 0, 0, 0, ""},
911  { "ENDPOINT", 0, 0, 0, ""},
912  { "ENVELOPE", 0, 0, 0, ""},
913  { "EQUALS", 0, 0, 0, ""},
914  { "EXTERIORRING", 0, 0, 0, ""},
915  { "EXTRACT", 0, 0, 0, ""},
916  { "EXP", 0, 0, 0, ""},
917  { "EXPORT_SET", 0, 0, 0, ""},
918  { "FIELD", 0, 0, 0, ""},
919  { "FIND_IN_SET", 0, 0, 0, ""},
920  { "FLOOR", 0, 0, 0, ""},
921  { "FORMAT", 0, 0, 0, ""},
922  { "FOUND_ROWS", 0, 0, 0, ""},
923  { "FROM_DAYS", 0, 0, 0, ""},
924  { "FROM_UNIXTIME", 0, 0, 0, ""},
925  { "GET_LOCK", 0, 0, 0, ""},
926  { "GEOMETRYN", 0, 0, 0, ""},
927  { "GEOMETRYTYPE", 0, 0, 0, ""},
928  { "GEOMCOLLFROMTEXT", 0, 0, 0, ""},
929  { "GEOMCOLLFROMWKB", 0, 0, 0, ""},
930  { "GEOMETRYCOLLECTIONFROMTEXT", 0, 0, 0, ""},
931  { "GEOMETRYCOLLECTIONFROMWKB", 0, 0, 0, ""},
932  { "GEOMETRYFROMTEXT", 0, 0, 0, ""},
933  { "GEOMETRYFROMWKB", 0, 0, 0, ""},
934  { "GEOMFROMTEXT", 0, 0, 0, ""},
935  { "GEOMFROMWKB", 0, 0, 0, ""},
936  { "GLENGTH", 0, 0, 0, ""},
937  { "GREATEST", 0, 0, 0, ""},
938  { "GROUP_CONCAT", 0, 0, 0, ""},
939  { "GROUP_UNIQUE_USERS", 0, 0, 0, ""},
940  { "HEX", 0, 0, 0, ""},
941  { "IFNULL", 0, 0, 0, ""},
942  { "INET_ATON", 0, 0, 0, ""},
943  { "INET_NTOA", 0, 0, 0, ""},
944  { "INSTR", 0, 0, 0, ""},
945  { "INTERIORRINGN", 0, 0, 0, ""},
946  { "INTERSECTS", 0, 0, 0, ""},
947  { "ISCLOSED", 0, 0, 0, ""},
948  { "ISEMPTY", 0, 0, 0, ""},
949  { "ISNULL", 0, 0, 0, ""},
950  { "IS_FREE_LOCK", 0, 0, 0, ""},
951  { "IS_USED_LOCK", 0, 0, 0, ""},
952  { "LAST_INSERT_ID", 0, 0, 0, ""},
953  { "ISSIMPLE", 0, 0, 0, ""},
954  { "LAST_DAY", 0, 0, 0, ""},
955  { "LCASE", 0, 0, 0, ""},
956  { "LEAST", 0, 0, 0, ""},
957  { "LENGTH", 0, 0, 0, ""},
958  { "LN", 0, 0, 0, ""},
959  { "LINEFROMTEXT", 0, 0, 0, ""},
960  { "LINEFROMWKB", 0, 0, 0, ""},
961  { "LINESTRINGFROMTEXT", 0, 0, 0, ""},
962  { "LINESTRINGFROMWKB", 0, 0, 0, ""},
963  { "LOAD_FILE", 0, 0, 0, ""},
964  { "LOCATE", 0, 0, 0, ""},
965  { "LOG", 0, 0, 0, ""},
966  { "LOG2", 0, 0, 0, ""},
967  { "LOG10", 0, 0, 0, ""},
968  { "LOWER", 0, 0, 0, ""},
969  { "LPAD", 0, 0, 0, ""},
970  { "LTRIM", 0, 0, 0, ""},
971  { "MAKE_SET", 0, 0, 0, ""},
972  { "MAKEDATE", 0, 0, 0, ""},
973  { "MAKETIME", 0, 0, 0, ""},
974  { "MASTER_POS_WAIT", 0, 0, 0, ""},
975  { "MAX", 0, 0, 0, ""},
976  { "MBRCONTAINS", 0, 0, 0, ""},
977  { "MBRDISJOINT", 0, 0, 0, ""},
978  { "MBREQUAL", 0, 0, 0, ""},
979  { "MBRINTERSECTS", 0, 0, 0, ""},
980  { "MBROVERLAPS", 0, 0, 0, ""},
981  { "MBRTOUCHES", 0, 0, 0, ""},
982  { "MBRWITHIN", 0, 0, 0, ""},
983  { "MD5", 0, 0, 0, ""},
984  { "MID", 0, 0, 0, ""},
985  { "MIN", 0, 0, 0, ""},
986  { "MLINEFROMTEXT", 0, 0, 0, ""},
987  { "MLINEFROMWKB", 0, 0, 0, ""},
988  { "MPOINTFROMTEXT", 0, 0, 0, ""},
989  { "MPOINTFROMWKB", 0, 0, 0, ""},
990  { "MPOLYFROMTEXT", 0, 0, 0, ""},
991  { "MPOLYFROMWKB", 0, 0, 0, ""},
992  { "MONTHNAME", 0, 0, 0, ""},
993  { "MULTILINESTRINGFROMTEXT", 0, 0, 0, ""},
994  { "MULTILINESTRINGFROMWKB", 0, 0, 0, ""},
995  { "MULTIPOINTFROMTEXT", 0, 0, 0, ""},
996  { "MULTIPOINTFROMWKB", 0, 0, 0, ""},
997  { "MULTIPOLYGONFROMTEXT", 0, 0, 0, ""},
998  { "MULTIPOLYGONFROMWKB", 0, 0, 0, ""},
999  { "NAME_CONST", 0, 0, 0, ""},
1000  { "NOW", 0, 0, 0, ""},
1001  { "NULLIF", 0, 0, 0, ""},
1002  { "NUMGEOMETRIES", 0, 0, 0, ""},
1003  { "NUMINTERIORRINGS", 0, 0, 0, ""},
1004  { "NUMPOINTS", 0, 0, 0, ""},
1005  { "OCTET_LENGTH", 0, 0, 0, ""},
1006  { "OCT", 0, 0, 0, ""},
1007  { "ORD", 0, 0, 0, ""},
1008  { "OVERLAPS", 0, 0, 0, ""},
1009  { "PERIOD_ADD", 0, 0, 0, ""},
1010  { "PERIOD_DIFF", 0, 0, 0, ""},
1011  { "PI", 0, 0, 0, ""},
1012  { "POINTFROMTEXT", 0, 0, 0, ""},
1013  { "POINTFROMWKB", 0, 0, 0, ""},
1014  { "POINTN", 0, 0, 0, ""},
1015  { "POLYFROMTEXT", 0, 0, 0, ""},
1016  { "POLYFROMWKB", 0, 0, 0, ""},
1017  { "POLYGONFROMTEXT", 0, 0, 0, ""},
1018  { "POLYGONFROMWKB", 0, 0, 0, ""},
1019  { "POSITION", 0, 0, 0, ""},
1020  { "POW", 0, 0, 0, ""},
1021  { "POWER", 0, 0, 0, ""},
1022  { "QUOTE", 0, 0, 0, ""},
1023  { "RADIANS", 0, 0, 0, ""},
1024  { "RAND", 0, 0, 0, ""},
1025  { "RELEASE_LOCK", 0, 0, 0, ""},
1026  { "REVERSE", 0, 0, 0, ""},
1027  { "ROUND", 0, 0, 0, ""},
1028  { "ROW_COUNT", 0, 0, 0, ""},
1029  { "RPAD", 0, 0, 0, ""},
1030  { "RTRIM", 0, 0, 0, ""},
1031  { "SEC_TO_TIME", 0, 0, 0, ""},
1032  { "SESSION_USER", 0, 0, 0, ""},
1033  { "SUBDATE", 0, 0, 0, ""},
1034  { "SIGN", 0, 0, 0, ""},
1035  { "SIN", 0, 0, 0, ""},
1036  { "SHA", 0, 0, 0, ""},
1037  { "SHA1", 0, 0, 0, ""},
1038  { "SLEEP", 0, 0, 0, ""},
1039  { "SOUNDEX", 0, 0, 0, ""},
1040  { "SPACE", 0, 0, 0, ""},
1041  { "SQRT", 0, 0, 0, ""},
1042  { "SRID", 0, 0, 0, ""},
1043  { "STARTPOINT", 0, 0, 0, ""},
1044  { "STD", 0, 0, 0, ""},
1045  { "STDDEV", 0, 0, 0, ""},
1046  { "STDDEV_POP", 0, 0, 0, ""},
1047  { "STDDEV_SAMP", 0, 0, 0, ""},
1048  { "STR_TO_DATE", 0, 0, 0, ""},
1049  { "STRCMP", 0, 0, 0, ""},
1050  { "SUBSTR", 0, 0, 0, ""},
1051  { "SUBSTRING", 0, 0, 0, ""},
1052  { "SUBSTRING_INDEX", 0, 0, 0, ""},
1053  { "SUBTIME", 0, 0, 0, ""},
1054  { "SUM", 0, 0, 0, ""},
1055  { "SYSDATE", 0, 0, 0, ""},
1056  { "SYSTEM_USER", 0, 0, 0, ""},
1057  { "TAN", 0, 0, 0, ""},
1058  { "TIME_FORMAT", 0, 0, 0, ""},
1059  { "TIME_TO_SEC", 0, 0, 0, ""},
1060  { "TIMEDIFF", 0, 0, 0, ""},
1061  { "TO_DAYS", 0, 0, 0, ""},
1062  { "TOUCHES", 0, 0, 0, ""},
1063  { "TRIM", 0, 0, 0, ""},
1064  { "UCASE", 0, 0, 0, ""},
1065  { "UNCOMPRESS", 0, 0, 0, ""},
1066  { "UNCOMPRESSED_LENGTH", 0, 0, 0, ""},
1067  { "UNHEX", 0, 0, 0, ""},
1068  { "UNIQUE_USERS", 0, 0, 0, ""},
1069  { "UNIX_TIMESTAMP", 0, 0, 0, ""},
1070  { "UPPER", 0, 0, 0, ""},
1071  { "UUID", 0, 0, 0, ""},
1072  { "VARIANCE", 0, 0, 0, ""},
1073  { "VAR_POP", 0, 0, 0, ""},
1074  { "VAR_SAMP", 0, 0, 0, ""},
1075  { "VERSION", 0, 0, 0, ""},
1076  { "WEEKDAY", 0, 0, 0, ""},
1077  { "WEEKOFYEAR", 0, 0, 0, ""},
1078  { "WITHIN", 0, 0, 0, ""},
1079  { "X", 0, 0, 0, ""},
1080  { "Y", 0, 0, 0, ""},
1081  { "YEARWEEK", 0, 0, 0, ""},
1082  /* end sentinel */
1083  { (char *)NULL, 0, 0, 0, ""}
1084 };
1085 
1086 static const char *load_default_groups[]= { "mysql","client",0 };
1087 
1088 static int embedded_server_arg_count= 0;
1089 static char *embedded_server_args[MAX_SERVER_ARGS];
1090 static const char *embedded_server_groups[]=
1091 { "server", "embedded", "mysql_SERVER", 0 };
1092 
1093 #ifdef HAVE_READLINE
1094 /*
1095  HIST_ENTRY is defined for libedit, but not for the real readline
1096  Need to redefine it for real readline to find it
1097 */
1098 #if !defined(HAVE_HIST_ENTRY)
1099 typedef struct _hist_entry {
1100  const char *line;
1101  const char *data;
1102 } HIST_ENTRY;
1103 #endif
1104 
1105 extern "C" int add_history(const char *command); /* From readline directory */
1106 extern "C" int read_history(const char *command);
1107 extern "C" int write_history(const char *command);
1108 extern "C" HIST_ENTRY *history_get(int num);
1109 extern "C" int history_length;
1110 static int not_in_history(const char *line);
1111 static void initialize_readline (char *name);
1112 static void fix_history(String *final_command);
1113 #endif
1114 
1115 static COMMANDS *find_command(char *name);
1116 static COMMANDS *find_command(char cmd_name);
1117 static bool add_line(String &buffer, char *line, ulong line_length,
1118  char *in_string, bool *ml_comment, bool truncated);
1119 static void remove_cntrl(String &buffer);
1120 static void print_table_data(MYSQL_RES *result);
1121 static void print_table_data_html(MYSQL_RES *result);
1122 static void print_table_data_xml(MYSQL_RES *result);
1123 static void print_tab_data(MYSQL_RES *result);
1124 static void print_table_data_vertically(MYSQL_RES *result);
1125 static void print_warnings(void);
1126 static ulong start_timer(void);
1127 static void end_timer(ulong start_time,char *buff);
1128 static void mysql_end_timer(ulong start_time,char *buff);
1129 static void nice_time(double sec,char *buff,bool part_second);
1130 extern "C" sig_handler mysql_end(int sig);
1131 extern "C" sig_handler handle_kill_signal(int sig);
1132 #if defined(HAVE_TERMIOS_H) && defined(GWINSZ_IN_SYS_IOCTL)
1133 static sig_handler window_resize(int sig);
1134 #endif
1135 
1136 const char DELIMITER_NAME[]= "delimiter";
1137 const uint DELIMITER_NAME_LEN= sizeof(DELIMITER_NAME) - 1;
1138 inline bool is_delimiter_command(char *name, ulong len)
1139 {
1140  /*
1141  Delimiter command has a parameter, so the length of the whole command
1142  is larger than DELIMITER_NAME_LEN. We don't care the parameter, so
1143  only name(first DELIMITER_NAME_LEN bytes) is checked.
1144  */
1145  return (len >= DELIMITER_NAME_LEN &&
1146  !my_strnncoll(charset_info, (uchar*) name, DELIMITER_NAME_LEN,
1147  (uchar *) DELIMITER_NAME, DELIMITER_NAME_LEN));
1148 }
1149 
1158 inline int get_command_index(char cmd_char)
1159 {
1160  /*
1161  All client-specific commands are in the first part of commands array
1162  and have a function to implement it.
1163  */
1164  for (uint i= 0; *commands[i].func; i++)
1165  if (commands[i].cmd_char == cmd_char)
1166  return i;
1167  return -1;
1168 }
1169 
1170 static int delimiter_index= -1;
1171 static int charset_index= -1;
1172 static bool real_binary_mode= FALSE;
1173 
1174 #ifdef _WIN32
1175 BOOL windows_ctrl_handler(DWORD fdwCtrlType)
1176 {
1177  switch (fdwCtrlType)
1178  {
1179  case CTRL_C_EVENT:
1180  case CTRL_BREAK_EVENT:
1181  if (!opt_sigint_ignore)
1182  handle_kill_signal(SIGINT);
1183  /* Indicate that signal has beed handled. */
1184  return TRUE;
1185  case CTRL_CLOSE_EVENT:
1186  case CTRL_LOGOFF_EVENT:
1187  case CTRL_SHUTDOWN_EVENT:
1188  handle_kill_signal(SIGINT + 1);
1189  }
1190  /* Pass signal to the next control handler function. */
1191  return FALSE;
1192 }
1193 #endif
1194 
1195 
1196 int main(int argc,char *argv[])
1197 {
1198  char buff[80];
1199 
1200  MY_INIT(argv[0]);
1201  DBUG_ENTER("main");
1202  DBUG_PROCESS(argv[0]);
1203 
1204  charset_index= get_command_index('C');
1205  delimiter_index= get_command_index('d');
1206  delimiter_str= delimiter;
1207  default_prompt = my_strdup(getenv("MYSQL_PS1") ?
1208  getenv("MYSQL_PS1") :
1209  "mysql> ",MYF(MY_WME));
1210  current_prompt = my_strdup(default_prompt,MYF(MY_WME));
1211  prompt_counter=0;
1212 
1213  outfile[0]=0; // no (default) outfile
1214  strmov(pager, "stdout"); // the default, if --pager wasn't given
1215  {
1216  char *tmp=getenv("PAGER");
1217  if (tmp && strlen(tmp))
1218  {
1219  default_pager_set= 1;
1220  strmov(default_pager, tmp);
1221  }
1222  }
1223  if (!isatty(0) || !isatty(1))
1224  {
1225  status.batch=1; opt_silent=1;
1226  ignore_errors=0;
1227  }
1228  else
1229  status.add_to_history=1;
1230  status.exit_status=1;
1231 
1232  {
1233  /*
1234  The file descriptor-layer may be out-of-sync with the file-number layer,
1235  so we make sure that "stdout" is really open. If its file is closed then
1236  explicitly close the FD layer.
1237  */
1238  int stdout_fileno_copy;
1239  stdout_fileno_copy= dup(fileno(stdout)); /* Okay if fileno fails. */
1240  if (stdout_fileno_copy == -1)
1241  fclose(stdout);
1242  else
1243  close(stdout_fileno_copy); /* Clean up dup(). */
1244  }
1245 
1246 #ifdef __WIN__
1247  /* Convert command line parameters from UTF16LE to UTF8MB4. */
1248  my_win_translate_command_line_args(&my_charset_utf8mb4_bin, &argc, &argv);
1249 #endif
1250 
1251  my_getopt_use_args_separator= TRUE;
1252  if (load_defaults("my",load_default_groups,&argc,&argv))
1253  {
1254  my_end(0);
1255  exit(1);
1256  }
1257  my_getopt_use_args_separator= FALSE;
1258 
1259  defaults_argv=argv;
1260  if (get_options(argc, (char **) argv))
1261  {
1262  free_defaults(defaults_argv);
1263  my_end(0);
1264  exit(1);
1265  }
1266  if (status.batch && !status.line_buff &&
1267  !(status.line_buff= batch_readline_init(MAX_BATCH_BUFFER_SIZE, stdin)))
1268  {
1269  put_info("Can't initialize batch_readline - may be the input source is "
1270  "a directory or a block device.", INFO_ERROR, 0);
1271  free_defaults(defaults_argv);
1272  my_end(0);
1273  exit(1);
1274  }
1275  if (mysql_server_init(embedded_server_arg_count, embedded_server_args,
1276  (char**) embedded_server_groups))
1277  {
1278  put_error(NULL);
1279  free_defaults(defaults_argv);
1280  my_end(0);
1281  exit(1);
1282  }
1283  glob_buffer.realloc(512);
1284  completion_hash_init(&ht, 128);
1285  init_alloc_root(&hash_mem_root, 16384, 0);
1286  memset(&mysql, 0, sizeof(mysql));
1287  if (sql_connect(current_host,current_db,current_user,opt_password,
1288  opt_silent))
1289  {
1290  quick= 1; // Avoid history
1291  status.exit_status= 1;
1292  mysql_end(-1);
1293  }
1294  if (!status.batch)
1295  ignore_errors=1; // Don't abort monitor
1296 
1297 #ifndef _WIN32
1298  if (opt_sigint_ignore)
1299  signal(SIGINT, SIG_IGN);
1300  else
1301  signal(SIGINT, handle_kill_signal); // Catch SIGINT to clean up
1302  signal(SIGQUIT, mysql_end); // Catch SIGQUIT to clean up
1303  signal(SIGHUP, handle_kill_signal); // Catch SIGHUP to clean up
1304 #else
1305  SetConsoleCtrlHandler((PHANDLER_ROUTINE) windows_ctrl_handler, TRUE);
1306 #endif
1307 
1308 
1309 #if defined(HAVE_TERMIOS_H) && defined(GWINSZ_IN_SYS_IOCTL)
1310  /* Readline will call this if it installs a handler */
1311  signal(SIGWINCH, window_resize);
1312  /* call the SIGWINCH handler to get the default term width */
1313  window_resize(0);
1314 #endif
1315 
1316  put_info("Welcome to the MySQL monitor. Commands end with ; or \\g.",
1317  INFO_INFO);
1318  sprintf((char*) glob_buffer.ptr(),
1319  "Your MySQL connection id is %lu\nServer version: %s\n",
1320  mysql_thread_id(&mysql), server_version_string(&mysql));
1321  put_info((char*) glob_buffer.ptr(),INFO_INFO);
1322 
1323  put_info(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"), INFO_INFO);
1324 
1325 #ifdef HAVE_READLINE
1326  initialize_readline((char*) my_progname);
1327  if (!status.batch && !quick && !opt_html && !opt_xml)
1328  {
1329  init_dynamic_string(&histignore_buffer, "*IDENTIFIED*:*PASSWORD*",
1330  1024, 1024);
1331 
1332  /*
1333  More history-ignore patterns can be supplied using either --histignore
1334  option or MYSQL_HISTIGNORE environment variable. If supplied, it will
1335  get appended to the default pattern (*IDENTIFIED*:*PASSWORD*). In case
1336  both are specified, pattern(s) supplied using --histignore option will
1337  be used.
1338  */
1339  if (opt_histignore)
1340  {
1341  dynstr_append(&histignore_buffer, ":");
1342  dynstr_append(&histignore_buffer, opt_histignore);
1343  }
1344  else if (getenv("MYSQL_HISTIGNORE"))
1345  {
1346  dynstr_append(&histignore_buffer, ":");
1347  dynstr_append(&histignore_buffer, getenv("MYSQL_HISTIGNORE"));
1348  }
1349 
1350  parse_histignore();
1351 
1352  /* read-history from file, default ~/.mysql_history*/
1353  if (getenv("MYSQL_HISTFILE"))
1354  histfile=my_strdup(getenv("MYSQL_HISTFILE"),MYF(MY_WME));
1355  else if (getenv("HOME"))
1356  {
1357  histfile=(char*) my_malloc((uint) strlen(getenv("HOME"))
1358  + (uint) strlen("/.mysql_history")+2,
1359  MYF(MY_WME));
1360  if (histfile)
1361  sprintf(histfile,"%s/.mysql_history",getenv("HOME"));
1362  char link_name[FN_REFLEN];
1363  if (my_readlink(link_name, histfile, 0) == 0 &&
1364  strncmp(link_name, "/dev/null", 10) == 0)
1365  {
1366  /* The .mysql_history file is a symlink to /dev/null, don't use it */
1367  my_free(histfile);
1368  histfile= 0;
1369  }
1370  }
1371 
1372  /* We used to suggest setting MYSQL_HISTFILE=/dev/null. */
1373  if (histfile && strncmp(histfile, "/dev/null", 10) == 0)
1374  histfile= NULL;
1375 
1376  if (histfile && histfile[0])
1377  {
1378  if (verbose)
1379  tee_fprintf(stdout, "Reading history-file %s\n",histfile);
1380  read_history(histfile);
1381  if (!(histfile_tmp= (char*) my_malloc((uint) strlen(histfile) + 5,
1382  MYF(MY_WME))))
1383  {
1384  fprintf(stderr, "Couldn't allocate memory for temp histfile!\n");
1385  exit(1);
1386  }
1387  sprintf(histfile_tmp, "%s.TMP", histfile);
1388  }
1389  }
1390 
1391 #endif
1392 
1393  sprintf(buff, "%s",
1394  "Type 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n");
1395  put_info(buff,INFO_INFO);
1396  status.exit_status= read_and_execute(!status.batch);
1397  if (opt_outfile)
1398  end_tee();
1399  mysql_end(0);
1400 #ifndef _lint
1401  DBUG_RETURN(0); // Keep compiler happy
1402 #endif
1403 }
1404 
1405 sig_handler mysql_end(int sig)
1406 {
1407  mysql_close(&mysql);
1408 #ifdef HAVE_READLINE
1409  if (!status.batch && !quick && !opt_html && !opt_xml &&
1410  histfile && histfile[0])
1411  {
1412  /* write-history */
1413  if (verbose)
1414  tee_fprintf(stdout, "Writing history-file %s\n",histfile);
1415  if (!write_history(histfile_tmp))
1416  my_rename(histfile_tmp, histfile, MYF(MY_WME));
1417  }
1418  batch_readline_end(status.line_buff);
1419  completion_hash_free(&ht);
1420  free_root(&hash_mem_root,MYF(0));
1421 
1422  my_free(opt_histignore);
1423  my_free(histfile);
1424  my_free(histfile_tmp);
1425  dynstr_free(&histignore_buffer);
1426  free_hist_patterns();
1427 #endif
1428  if (sig >= 0)
1429  put_info(sig ? "Aborted" : "Bye", INFO_RESULT);
1430  glob_buffer.free();
1431  old_buffer.free();
1432  processed_prompt.free();
1433  my_free(server_version);
1434  my_free(opt_password);
1435  my_free(opt_mysql_unix_port);
1436  my_free(current_db);
1437  my_free(current_host);
1438  my_free(current_user);
1439  my_free(full_username);
1440  my_free(part_username);
1441  my_free(default_prompt);
1442 #ifdef HAVE_SMEM
1443  my_free(shared_memory_base_name);
1444 #endif
1445  my_free(current_prompt);
1446  while (embedded_server_arg_count > 1)
1447  my_free(embedded_server_args[--embedded_server_arg_count]);
1448  mysql_server_end();
1449  free_defaults(defaults_argv);
1450  my_end(my_end_arg);
1451  exit(status.exit_status);
1452 }
1453 
1454 
1455 /*
1456  This function handles sigint calls
1457  If query is in process, kill query
1458  no query in process, terminate like previous behavior
1459  */
1460 sig_handler handle_kill_signal(int sig)
1461 {
1462  char kill_buffer[40];
1463  MYSQL *kill_mysql= NULL;
1464  const char *reason = sig == SIGINT ? "Ctrl-C" : "Terminal close";
1465 
1466  /* terminate if no query being executed, or we already tried interrupting */
1467  /* terminate if no query being executed, or we already tried interrupting */
1468  if (!executing_query || (interrupted_query == 2))
1469  {
1470  tee_fprintf(stdout, "%s -- exit!\n", reason);
1471  goto err;
1472  }
1473 
1474  kill_mysql= mysql_init(kill_mysql);
1475  mysql_options(kill_mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
1476  mysql_options4(kill_mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
1477  "program_name", "mysql");
1478  if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password,
1479  "", opt_mysql_port, opt_mysql_unix_port,0))
1480  {
1481  tee_fprintf(stdout, "%s -- sorry, cannot connect to server to kill query, giving up ...\n", reason);
1482  goto err;
1483  }
1484 
1485  interrupted_query++;
1486 
1487  /* mysqld < 5 does not understand KILL QUERY, skip to KILL CONNECTION */
1488  if ((interrupted_query == 1) && (mysql_get_server_version(&mysql) < 50000))
1489  interrupted_query= 2;
1490 
1491  /* kill_buffer is always big enough because max length of %lu is 15 */
1492  sprintf(kill_buffer, "KILL %s%lu",
1493  (interrupted_query == 1) ? "QUERY " : "",
1494  mysql_thread_id(&mysql));
1495  tee_fprintf(stdout, "%s -- sending \"%s\" to server ...\n",
1496  reason, kill_buffer);
1497  mysql_real_query(kill_mysql, kill_buffer, (uint) strlen(kill_buffer));
1498  mysql_close(kill_mysql);
1499  tee_fprintf(stdout, "%s -- query aborted.\n", reason);
1500 
1501  return;
1502 
1503 err:
1504 #ifdef _WIN32
1505  /*
1506  When SIGINT is raised on Windows, the OS creates a new thread to handle the
1507  interrupt. Once that thread completes, the main thread continues running
1508  only to find that it's resources have already been free'd when the sigint
1509  handler called mysql_end().
1510  */
1511  mysql_thread_end();
1512  return;
1513 #else
1514  mysql_end(sig);
1515 #endif
1516 }
1517 
1518 
1519 #if defined(HAVE_TERMIOS_H) && defined(GWINSZ_IN_SYS_IOCTL)
1520 sig_handler window_resize(int sig)
1521 {
1522  struct winsize window_size;
1523 
1524  if (ioctl(fileno(stdin), TIOCGWINSZ, &window_size) == 0)
1525  terminal_width= window_size.ws_col;
1526 }
1527 #endif
1528 
1529 static struct my_option my_long_options[] =
1530 {
1531  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
1532  0, 0, 0, 0, 0},
1533  {"help", 'I', "Synonym for -?", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
1534  0, 0, 0, 0, 0},
1535  {"auto-rehash", OPT_AUTO_REHASH,
1536  "Enable automatic rehashing. One doesn't need to use 'rehash' to get table "
1537  "and field completion, but startup and reconnecting may take a longer time. "
1538  "Disable with --disable-auto-rehash.",
1539  &opt_rehash, &opt_rehash, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0,
1540  0, 0},
1541  {"no-auto-rehash", 'A',
1542  "No automatic rehashing. One has to use 'rehash' to get table and field "
1543  "completion. This gives a quicker start of mysql and disables rehashing "
1544  "on reconnect.",
1545  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
1546  {"auto-vertical-output", OPT_AUTO_VERTICAL_OUTPUT,
1547  "Automatically switch to vertical output mode if the result is wider "
1548  "than the terminal width.",
1549  &auto_vertical_output, &auto_vertical_output, 0, GET_BOOL, NO_ARG, 0,
1550  0, 0, 0, 0, 0},
1551  {"batch", 'B',
1552  "Don't use history file. Disable interactive behavior. (Enables --silent.)",
1553  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
1554  {"bind-address", 0, "IP address to bind to.",
1555  (uchar**) &opt_bind_addr, (uchar**) &opt_bind_addr, 0, GET_STR,
1556  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1557  {"character-sets-dir", OPT_CHARSETS_DIR,
1558  "Directory for character set files.", &charsets_dir,
1559  &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1560  {"column-type-info", OPT_COLUMN_TYPES, "Display column type information.",
1561  &column_types_flag, &column_types_flag,
1562  0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1563  {"comments", 'c', "Preserve comments. Send comments to the server."
1564  " The default is --skip-comments (discard comments), enable with --comments.",
1565  &preserve_comments, &preserve_comments,
1566  0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1567  {"compress", 'C', "Use compression in server/client protocol.",
1568  &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
1569  0, 0, 0},
1570 #ifdef DBUG_OFF
1571  {"debug", '#', "This is a non-debug version. Catch this and exit.",
1572  0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
1573 #else
1574  {"debug", '#', "Output debug log.", &default_dbug_option,
1575  &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
1576 #endif
1577  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
1578  &debug_check_flag, &debug_check_flag, 0,
1579  GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1580  {"debug-info", 'T', "Print some debug info at exit.", &debug_info_flag,
1581  &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1582  {"database", 'D', "Database to use.", &current_db,
1583  &current_db, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1584  {"default-character-set", OPT_DEFAULT_CHARSET,
1585  "Set the default character set.", &default_charset,
1586  &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1587  {"delimiter", OPT_DELIMITER, "Delimiter to be used.", &delimiter_str,
1588  &delimiter_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1589  {"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN,
1590  "Enable/disable the clear text authentication plugin.",
1591  &opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin,
1592  0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
1593  {"execute", 'e', "Execute command and quit. (Disables --force and history file.)", 0,
1594  0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1595  {"vertical", 'E', "Print the output of a query (rows) vertically.",
1596  &vertical, &vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
1597  0},
1598  {"force", 'f', "Continue even if we get an SQL error.",
1599  &ignore_errors, &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
1600  0, 0, 0, 0},
1601  {"named-commands", 'G',
1602  "Enable named commands. Named commands mean this program's internal "
1603  "commands; see mysql> help . When enabled, the named commands can be "
1604  "used from any line of the query, otherwise only from the first line, "
1605  "before an enter. Disable with --disable-named-commands. This option "
1606  "is disabled by default.",
1607  &named_cmds, &named_cmds, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1608  0, 0},
1609  {"ignore-spaces", 'i', "Ignore space after function names.",
1610  &ignore_spaces, &ignore_spaces, 0, GET_BOOL, NO_ARG, 0, 0,
1611  0, 0, 0, 0},
1612  {"init-command", OPT_INIT_COMMAND,
1613  "SQL Command to execute when connecting to MySQL server. Will "
1614  "automatically be re-executed when reconnecting.",
1615  &opt_init_command, &opt_init_command, 0,
1616  GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1617  {"local-infile", OPT_LOCAL_INFILE, "Enable/disable LOAD DATA LOCAL INFILE.",
1618  &opt_local_infile, &opt_local_infile, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
1619  {"no-beep", 'b', "Turn off beep on error.", &opt_nobeep,
1620  &opt_nobeep, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1621  {"host", 'h', "Connect to host.", &current_host,
1622  &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1623  {"html", 'H', "Produce HTML output.", &opt_html, &opt_html,
1624  0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1625  {"xml", 'X', "Produce XML output.", &opt_xml, &opt_xml, 0,
1626  GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1627  {"line-numbers", OPT_LINE_NUMBERS, "Write line numbers for errors.",
1628  &line_numbers, &line_numbers, 0, GET_BOOL,
1629  NO_ARG, 1, 0, 0, 0, 0, 0},
1630  {"skip-line-numbers", 'L', "Don't write line number for errors.", 0, 0, 0, GET_NO_ARG,
1631  NO_ARG, 0, 0, 0, 0, 0, 0},
1632  {"unbuffered", 'n', "Flush buffer after each query.", &unbuffered,
1633  &unbuffered, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1634  {"column-names", OPT_COLUMN_NAMES, "Write column names in results.",
1635  &column_names, &column_names, 0, GET_BOOL,
1636  NO_ARG, 1, 0, 0, 0, 0, 0},
1637  {"skip-column-names", 'N',
1638  "Don't write column names in results.",
1639  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
1640  {"sigint-ignore", OPT_SIGINT_IGNORE, "Ignore SIGINT (CTRL-C).",
1641  &opt_sigint_ignore, &opt_sigint_ignore, 0, GET_BOOL,
1642  NO_ARG, 0, 0, 0, 0, 0, 0},
1643  {"one-database", 'o',
1644  "Ignore statements except those that occur while the default "
1645  "database is the one named at the command line.",
1646  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
1647 #ifdef USE_POPEN
1648  {"pager", OPT_PAGER,
1649  "Pager to use to display results. If you don't supply an option, the "
1650  "default pager is taken from your ENV variable PAGER. Valid pagers are "
1651  "less, more, cat [> filename], etc. See interactive help (\\h) also. "
1652  "This option does not work in batch mode. Disable with --disable-pager. "
1653  "This option is disabled by default.",
1654  0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
1655 #endif
1656  {"password", 'p',
1657  "Password to use when connecting to server. If password is not given it's asked from the tty.",
1658  0, 0, 0, GET_PASSWORD, OPT_ARG, 0, 0, 0, 0, 0, 0},
1659 #ifdef __WIN__
1660  {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
1661  NO_ARG, 0, 0, 0, 0, 0, 0},
1662 #endif
1663  {"port", 'P', "Port number to use for connection or 0 for default to, in "
1664  "order of preference, my.cnf, $MYSQL_TCP_PORT, "
1665 #if MYSQL_PORT_DEFAULT == 0
1666  "/etc/services, "
1667 #endif
1668  "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
1669  &opt_mysql_port,
1670  &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1671  {"prompt", OPT_PROMPT, "Set the mysql prompt to this value.",
1672  &current_prompt, &current_prompt, 0, GET_STR_ALLOC,
1673  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1674  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol to use for connection (tcp, socket, pipe, memory).",
1675  0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1676  {"quick", 'q',
1677  "Don't cache result, print it row by row. This may slow down the server "
1678  "if the output is suspended. Doesn't use history file.",
1679  &quick, &quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1680  {"raw", 'r', "Write fields without conversion. Used with --batch.",
1681  &opt_raw_data, &opt_raw_data, 0, GET_BOOL, NO_ARG, 0, 0, 0,
1682  0, 0, 0},
1683  {"reconnect", OPT_RECONNECT, "Reconnect if the connection is lost. Disable "
1684  "with --disable-reconnect. This option is enabled by default.",
1685  &opt_reconnect, &opt_reconnect, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
1686  {"silent", 's', "Be more silent. Print results with a tab as separator, "
1687  "each row on new line.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
1688 #ifdef HAVE_SMEM
1689  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
1690  "Base name of shared memory.", &shared_memory_base_name,
1691  &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1692 #endif
1693  {"socket", 'S', "The socket file to use for connection.",
1694  &opt_mysql_unix_port, &opt_mysql_unix_port, 0, GET_STR_ALLOC,
1695  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1696 #include "sslopt-longopts.h"
1697  {"table", 't', "Output in table format.", &output_tables,
1698  &output_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1699  {"tee", OPT_TEE,
1700  "Append everything into outfile. See interactive help (\\h) also. "
1701  "Does not work in batch mode. Disable with --disable-tee. "
1702  "This option is disabled by default.",
1703  0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1704 #ifndef DONT_ALLOW_USER_CHANGE
1705  {"user", 'u', "User for login if not current user.", &current_user,
1706  &current_user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1707 #endif
1708  {"safe-updates", 'U', "Only allow UPDATE and DELETE that uses keys.",
1709  &safe_updates, &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0,
1710  0, 0, 0, 0},
1711  {"i-am-a-dummy", 'U', "Synonym for option --safe-updates, -U.",
1712  &safe_updates, &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0,
1713  0, 0, 0, 0},
1714  {"verbose", 'v', "Write more. (-v -v -v gives the table output format).", 0,
1715  0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
1716  {"version", 'V', "Output version information and exit.", 0, 0, 0,
1717  GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
1718  {"wait", 'w', "Wait and retry if connection is down.", 0, 0, 0, GET_NO_ARG,
1719  NO_ARG, 0, 0, 0, 0, 0, 0},
1720  {"connect_timeout", OPT_CONNECT_TIMEOUT,
1721  "Number of seconds before connection timeout.",
1722  &opt_connect_timeout, &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG,
1723  0, 0, 3600*12, 0, 0, 0},
1724  {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET,
1725  "The maximum packet length to send to or receive from server.",
1726  &opt_max_allowed_packet, &opt_max_allowed_packet, 0,
1727  GET_ULONG, REQUIRED_ARG, 16 *1024L*1024L, 4096,
1728  (longlong) 2*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
1729  {"net_buffer_length", OPT_NET_BUFFER_LENGTH,
1730  "The buffer size for TCP/IP and socket communication.",
1731  &opt_net_buffer_length, &opt_net_buffer_length, 0, GET_ULONG,
1732  REQUIRED_ARG, 16384, 1024, 512*1024*1024L, MALLOC_OVERHEAD, 1024, 0},
1733  {"select_limit", OPT_SELECT_LIMIT,
1734  "Automatic limit for SELECT when using --safe-updates.",
1735  &select_limit, &select_limit, 0, GET_ULONG, REQUIRED_ARG, 1000L,
1736  1, ULONG_MAX, 0, 1, 0},
1737  {"max_join_size", OPT_MAX_JOIN_SIZE,
1738  "Automatic limit for rows in a join when using --safe-updates.",
1739  &max_join_size, &max_join_size, 0, GET_ULONG, REQUIRED_ARG, 1000000L,
1740  1, ULONG_MAX, 0, 1, 0},
1741  {"secure-auth", OPT_SECURE_AUTH, "Refuse client connecting to server if it"
1742  " uses old (pre-4.1.1) protocol.", &opt_secure_auth,
1743  &opt_secure_auth, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
1744  {"server-arg", OPT_SERVER_ARG, "Send embedded server this as a parameter.",
1745  0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1746  {"show-warnings", OPT_SHOW_WARNINGS, "Show warnings after every statement.",
1747  &show_warnings, &show_warnings, 0, GET_BOOL, NO_ARG,
1748  0, 0, 0, 0, 0, 0},
1749  {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
1750  &opt_plugin_dir, &opt_plugin_dir, 0,
1751  GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1752  {"default_auth", OPT_DEFAULT_AUTH,
1753  "Default authentication client-side plugin to use.",
1754  &opt_default_auth, &opt_default_auth, 0,
1755  GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1756  {"histignore", OPT_HISTIGNORE, "A colon-separated list of patterns "
1757  "to keep statements from getting logged into mysql history.",
1758  &opt_histignore, &opt_histignore, 0, GET_STR_ALLOC, REQUIRED_ARG,
1759  0, 0, 0, 0, 0, 0},
1760  {"binary-mode", OPT_BINARY_MODE,
1761  "By default, ASCII '\\0' is disallowed and '\\r\\n' is translated to '\\n'. "
1762  "This switch turns off both features, and also turns off parsing of all client"
1763  "commands except \\C and DELIMITER, in non-interactive mode (for input "
1764  "piped to mysql or loaded using the 'source' command). This is necessary "
1765  "when processing output from mysqlbinlog that may contain blobs.",
1766  &opt_binary_mode, &opt_binary_mode, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1767 #if !defined(HAVE_YASSL)
1768  {"server-public-key-path", OPT_SERVER_PUBLIC_KEY,
1769  "File path to the server public RSA key in PEM format.",
1770  &opt_server_public_key, &opt_server_public_key, 0,
1771  GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1772 #endif
1773  {"connect-expired-password", 0,
1774  "Notify the server that this client is prepared to handle expired "
1775  "password sandbox mode.",
1776  &opt_connect_expired_password, &opt_connect_expired_password, 0, GET_BOOL,
1777  NO_ARG, 0, 0, 0, 0, 0, 0},
1778  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
1779 };
1780 
1781 
1782 static void usage(int version)
1783 {
1784 #if defined(USE_LIBEDIT_INTERFACE)
1785  const char* readline= "";
1786 #else
1787  const char* readline= "readline";
1788 #endif
1789 
1790 #ifdef HAVE_READLINE
1791  printf("%s Ver %s Distrib %s, for %s (%s) using %s %s\n",
1792  my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE,
1793  readline, rl_library_version);
1794 #else
1795  printf("%s Ver %s Distrib %s, for %s (%s)\n", my_progname, VER,
1796  MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
1797 #endif
1798 
1799  if (version)
1800  return;
1801  puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
1802  printf("Usage: %s [OPTIONS] [database]\n", my_progname);
1803  my_print_help(my_long_options);
1804  print_defaults("my", load_default_groups);
1805  my_print_variables(my_long_options);
1806 }
1807 
1808 
1809 my_bool
1810 get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
1811  char *argument)
1812 {
1813  switch(optid) {
1814  case OPT_CHARSETS_DIR:
1815  strmake(mysql_charsets_dir, argument, sizeof(mysql_charsets_dir) - 1);
1816  charsets_dir = mysql_charsets_dir;
1817  break;
1818  case OPT_DELIMITER:
1819  if (argument == disabled_my_option)
1820  {
1821  strmov(delimiter, DEFAULT_DELIMITER);
1822  }
1823  else
1824  {
1825  /* Check that delimiter does not contain a backslash */
1826  if (!strstr(argument, "\\"))
1827  {
1828  strmake(delimiter, argument, sizeof(delimiter) - 1);
1829  }
1830  else
1831  {
1832  put_info("DELIMITER cannot contain a backslash character", INFO_ERROR);
1833  return 0;
1834  }
1835  }
1836  delimiter_length= (uint)strlen(delimiter);
1837  delimiter_str= delimiter;
1838  break;
1839  case OPT_LOCAL_INFILE:
1840  using_opt_local_infile=1;
1841  break;
1842  case OPT_ENABLE_CLEARTEXT_PLUGIN:
1843  using_opt_enable_cleartext_plugin= TRUE;
1844  break;
1845  case OPT_TEE:
1846  if (argument == disabled_my_option)
1847  {
1848  if (opt_outfile)
1849  end_tee();
1850  }
1851  else
1852  init_tee(argument);
1853  break;
1854  case OPT_PAGER:
1855  if (argument == disabled_my_option)
1856  opt_nopager= 1;
1857  else
1858  {
1859  opt_nopager= 0;
1860  if (argument && strlen(argument))
1861  {
1862  default_pager_set= 1;
1863  strmake(pager, argument, sizeof(pager) - 1);
1864  strmov(default_pager, pager);
1865  }
1866  else if (default_pager_set)
1867  strmov(pager, default_pager);
1868  else
1869  opt_nopager= 1;
1870  }
1871  break;
1872  case OPT_MYSQL_PROTOCOL:
1873 #ifndef EMBEDDED_LIBRARY
1874  opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
1875  opt->name);
1876 #endif
1877  break;
1878  case OPT_SERVER_ARG:
1879 #ifdef EMBEDDED_LIBRARY
1880  /*
1881  When the embedded server is being tested, the client needs to be
1882  able to pass command-line arguments to the embedded server so it can
1883  locate the language files and data directory.
1884  */
1885  if (!embedded_server_arg_count)
1886  {
1887  embedded_server_arg_count= 1;
1888  embedded_server_args[0]= (char*) "";
1889  }
1890  if (embedded_server_arg_count == MAX_SERVER_ARGS-1 ||
1891  !(embedded_server_args[embedded_server_arg_count++]=
1892  my_strdup(argument, MYF(MY_FAE))))
1893  {
1894  put_info("Can't use server argument", INFO_ERROR);
1895  return 0;
1896  }
1897 #else /*EMBEDDED_LIBRARY */
1898  printf("WARNING: --server-arg option not supported in this configuration.\n");
1899 #endif
1900  break;
1901  case 'A':
1902  opt_rehash= 0;
1903  break;
1904  case 'N':
1905  column_names= 0;
1906  break;
1907  case 'e':
1908  status.batch= 1;
1909  status.add_to_history= 0;
1910  if (!status.line_buff)
1911  ignore_errors= 0; // do it for the first -e only
1912  if (!(status.line_buff= batch_readline_command(status.line_buff, argument)))
1913  return 1;
1914  break;
1915  case 'o':
1916  if (argument == disabled_my_option)
1917  one_database= 0;
1918  else
1919  one_database= skip_updates= 1;
1920  break;
1921  case 'p':
1922  if (argument == disabled_my_option)
1923  argument= (char*) ""; // Don't require password
1924  if (argument)
1925  {
1926  char *start= argument;
1927  my_free(opt_password);
1928  opt_password= my_strdup(argument, MYF(MY_FAE));
1929  while (*argument) *argument++= 'x'; // Destroy argument
1930  if (*start)
1931  start[1]=0 ;
1932  tty_password= 0;
1933  }
1934  else
1935  tty_password= 1;
1936  break;
1937  case '#':
1938  DBUG_PUSH(argument ? argument : default_dbug_option);
1939  debug_info_flag= 1;
1940  break;
1941  case 's':
1942  if (argument == disabled_my_option)
1943  opt_silent= 0;
1944  else
1945  opt_silent++;
1946  break;
1947  case 'v':
1948  if (argument == disabled_my_option)
1949  verbose= 0;
1950  else
1951  verbose++;
1952  break;
1953  case 'B':
1954  status.batch= 1;
1955  status.add_to_history= 0;
1956  set_if_bigger(opt_silent,1); // more silent
1957  break;
1958  case 'W':
1959 #ifdef __WIN__
1960  opt_protocol = MYSQL_PROTOCOL_PIPE;
1961 #endif
1962  break;
1963 #include <sslopt-case.h>
1964  case 'V':
1965  usage(1);
1966  exit(0);
1967  case 'I':
1968  case '?':
1969  usage(0);
1970  exit(0);
1971  }
1972  return 0;
1973 }
1974 
1975 
1976 static int get_options(int argc, char **argv)
1977 {
1978  char *tmp, *pagpoint;
1979  int ho_error;
1980  MYSQL_PARAMETERS *mysql_params= mysql_get_parameters();
1981 
1982  tmp= (char *) getenv("MYSQL_HOST");
1983  if (tmp)
1984  current_host= my_strdup(tmp, MYF(MY_WME));
1985 
1986  pagpoint= getenv("PAGER");
1987  if (!((char*) (pagpoint)))
1988  {
1989  strmov(pager, "stdout");
1990  opt_nopager= 1;
1991  }
1992  else
1993  strmov(pager, pagpoint);
1994  strmov(default_pager, pager);
1995 
1996  opt_max_allowed_packet= *mysql_params->p_max_allowed_packet;
1997  opt_net_buffer_length= *mysql_params->p_net_buffer_length;
1998 
1999  if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
2000  exit(ho_error);
2001 
2002  *mysql_params->p_max_allowed_packet= opt_max_allowed_packet;
2003  *mysql_params->p_net_buffer_length= opt_net_buffer_length;
2004 
2005  if (status.batch) /* disable pager and outfile in this case */
2006  {
2007  strmov(default_pager, "stdout");
2008  strmov(pager, "stdout");
2009  opt_nopager= 1;
2010  default_pager_set= 0;
2011  opt_outfile= 0;
2012  opt_reconnect= 0;
2013  connect_flag= 0; /* Not in interactive mode */
2014  }
2015 
2016  if (argc > 1)
2017  {
2018  usage(0);
2019  exit(1);
2020  }
2021  if (argc == 1)
2022  {
2023  skip_updates= 0;
2024  my_free(current_db);
2025  current_db= my_strdup(*argv, MYF(MY_WME));
2026  }
2027  if (tty_password)
2028  opt_password= get_tty_password(NullS);
2029  if (debug_info_flag)
2030  my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
2031  if (debug_check_flag)
2032  my_end_arg= MY_CHECK_ERROR;
2033 
2034  if (ignore_spaces)
2035  connect_flag|= CLIENT_IGNORE_SPACE;
2036 
2037  return(0);
2038 }
2039 
2040 static int read_and_execute(bool interactive)
2041 {
2042 #if defined(__WIN__)
2043  String tmpbuf;
2044  String buffer;
2045 #endif
2046 
2047  char *line= NULL;
2048  char in_string=0;
2049  ulong line_number=0;
2050  bool ml_comment= 0;
2051  COMMANDS *com;
2052  ulong line_length= 0;
2053  status.exit_status=1;
2054 
2055  real_binary_mode= !interactive && opt_binary_mode;
2056  for (;;)
2057  {
2058  if (!interactive)
2059  {
2060  /*
2061  batch_readline can return 0 on EOF or error.
2062  In that case, we need to double check that we have a valid
2063  line before actually setting line_length to read_length.
2064  */
2065  line= batch_readline(status.line_buff, real_binary_mode);
2066  if (line)
2067  {
2068  line_length= status.line_buff->read_length;
2069 
2070  /*
2071  ASCII 0x00 is not allowed appearing in queries if it is not in binary
2072  mode.
2073  */
2074  if (!real_binary_mode && strlen(line) != line_length)
2075  {
2076  status.exit_status= 1;
2077  String msg;
2078  msg.append("ASCII '\\0' appeared in the statement, but this is not "
2079  "allowed unless option --binary-mode is enabled and mysql is "
2080  "run in non-interactive mode. Set --binary-mode to 1 if ASCII "
2081  "'\\0' is expected. Query: '");
2082  msg.append(glob_buffer);
2083  msg.append(line);
2084  msg.append("'.");
2085  put_info(msg.c_ptr(), INFO_ERROR);
2086  break;
2087  }
2088 
2089  /*
2090  Skip UTF8 Byte Order Marker (BOM) 0xEFBBBF.
2091  Editors like "notepad" put this marker in
2092  the very beginning of a text file when
2093  you save the file using "Unicode UTF-8" format.
2094  */
2095  if (!line_number &&
2096  (uchar) line[0] == 0xEF &&
2097  (uchar) line[1] == 0xBB &&
2098  (uchar) line[2] == 0xBF)
2099  {
2100  line+= 3;
2101  // decrease the line length accordingly to the 3 bytes chopped
2102  line_length -=3;
2103  }
2104  }
2105  line_number++;
2106  if (!glob_buffer.length())
2107  status.query_start_line=line_number;
2108  }
2109  else
2110  {
2111  char *prompt= (char*) (ml_comment ? " /*> " :
2112  glob_buffer.is_empty() ? construct_prompt() :
2113  !in_string ? " -> " :
2114  in_string == '\'' ?
2115  " '> " : (in_string == '`' ?
2116  " `> " :
2117  " \"> "));
2118  if (opt_outfile && glob_buffer.is_empty())
2119  fflush(OUTFILE);
2120 
2121 #if defined(__WIN__)
2122  tee_fputs(prompt, stdout);
2123  if (!tmpbuf.is_alloced())
2124  tmpbuf.alloc(65535);
2125  tmpbuf.length(0);
2126  buffer.length(0);
2127  line= my_win_console_readline(charset_info,
2128  (char *) tmpbuf.ptr(),
2129  tmpbuf.alloced_length());
2130 #else
2131  if (opt_outfile)
2132  fputs(prompt, OUTFILE);
2133  /*
2134  free the previous entered line.
2135  Note: my_free() cannot be used here as the memory was allocated under
2136  the readline/libedit library.
2137  */
2138  if (line)
2139  free(line);
2140  line= readline(prompt);
2141 #endif /* defined(__WIN__) */
2142 
2143  /*
2144  When Ctrl+d or Ctrl+z is pressed, the line may be NULL on some OS
2145  which may cause coredump.
2146  */
2147  if (opt_outfile && line)
2148  fprintf(OUTFILE, "%s\n", line);
2149 
2150  line_length= line ? strlen(line) : 0;
2151  }
2152  // End of file or system error
2153  if (!line)
2154  {
2155  if (status.line_buff && status.line_buff->error)
2156  status.exit_status= 1;
2157  else
2158  status.exit_status= 0;
2159  break;
2160  }
2161 
2162  /*
2163  Check if line is a mysql command line
2164  (We want to allow help, print and clear anywhere at line start
2165  */
2166  if ((named_cmds || glob_buffer.is_empty())
2167  && !ml_comment && !in_string && (com= find_command(line)))
2168  {
2169  if ((*com->func)(&glob_buffer,line) > 0)
2170  break;
2171  if (glob_buffer.is_empty()) // If buffer was emptied
2172  in_string=0;
2173 #ifdef HAVE_READLINE
2174  if (interactive && status.add_to_history && not_in_history(line))
2175  add_filtered_history(line);
2176 #endif
2177  continue;
2178  }
2179  if (add_line(glob_buffer, line, line_length, &in_string, &ml_comment,
2180  status.line_buff ? status.line_buff->truncated : 0))
2181  break;
2182  }
2183  /* if in batch mode, send last query even if it doesn't end with \g or go */
2184 
2185  if (!interactive && !status.exit_status)
2186  {
2187  remove_cntrl(glob_buffer);
2188  if (!glob_buffer.is_empty())
2189  {
2190  status.exit_status=1;
2191  if (com_go(&glob_buffer,line) <= 0)
2192  status.exit_status=0;
2193  }
2194  }
2195 
2196 #if defined(__WIN__)
2197  buffer.free();
2198  tmpbuf.free();
2199 #else
2200  if (interactive)
2201  /*
2202  free the last entered line.
2203  Note: my_free() cannot be used here as the memory was allocated under
2204  the readline/libedit library.
2205  */
2206  free(line);
2207 #endif
2208 
2209  /*
2210  If the function is called by 'source' command, it will return to interactive
2211  mode, so real_binary_mode should be FALSE. Otherwise, it will exit the
2212  program, it is safe to set real_binary_mode to FALSE.
2213  */
2214  real_binary_mode= FALSE;
2215  return status.exit_status;
2216 }
2217 
2228 static COMMANDS *find_command(char cmd_char)
2229 {
2230  DBUG_ENTER("find_command");
2231  DBUG_PRINT("enter", ("cmd_char: %d", cmd_char));
2232 
2233  int index= -1;
2234 
2235  /*
2236  In binary-mode, we disallow all mysql commands except '\C'
2237  and DELIMITER.
2238  */
2239  if (real_binary_mode)
2240  {
2241  if (cmd_char == 'C')
2242  index= charset_index;
2243  }
2244  else
2245  index= get_command_index(cmd_char);
2246 
2247  if (index >= 0)
2248  {
2249  DBUG_PRINT("exit",("found command: %s", commands[index].name));
2250  DBUG_RETURN(&commands[index]);
2251  }
2252  else
2253  DBUG_RETURN((COMMANDS *) 0);
2254 }
2255 
2265 static COMMANDS *find_command(char *name)
2266 {
2267  uint len;
2268  char *end;
2269  DBUG_ENTER("find_command");
2270 
2271  DBUG_ASSERT(name != NULL);
2272  DBUG_PRINT("enter", ("name: '%s'", name));
2273 
2274  while (my_isspace(charset_info, *name))
2275  name++;
2276  /*
2277  If there is an \\g in the row or if the row has a delimiter but
2278  this is not a delimiter command, let add_line() take care of
2279  parsing the row and calling find_command().
2280  */
2281  if ((!real_binary_mode && strstr(name, "\\g")) ||
2282  (strstr(name, delimiter) &&
2283  !is_delimiter_command(name, DELIMITER_NAME_LEN)))
2284  DBUG_RETURN((COMMANDS *) 0);
2285 
2286  if ((end=strcont(name, " \t")))
2287  {
2288  len=(uint) (end - name);
2289  while (my_isspace(charset_info, *end))
2290  end++;
2291  if (!*end)
2292  end= 0; // no arguments to function
2293  }
2294  else
2295  len= (uint) strlen(name);
2296 
2297  int index= -1;
2298  if (real_binary_mode)
2299  {
2300  if (is_delimiter_command(name, len))
2301  index= delimiter_index;
2302  }
2303  else
2304  {
2305  /*
2306  All commands are in the first part of commands array and have a function
2307  to implement it.
2308  */
2309  for (uint i= 0; commands[i].func; i++)
2310  {
2311  if (!my_strnncoll(&my_charset_latin1, (uchar*) name, len,
2312  (uchar*) commands[i].name, len) &&
2313  (commands[i].name[len] == '\0') &&
2314  (!end || commands[i].takes_params))
2315  {
2316  index= i;
2317  break;
2318  }
2319  }
2320  }
2321 
2322  if (index >= 0)
2323  {
2324  DBUG_PRINT("exit", ("found command: %s", commands[index].name));
2325  DBUG_RETURN(&commands[index]);
2326  }
2327  DBUG_RETURN((COMMANDS *) 0);
2328 }
2329 
2330 
2331 static bool add_line(String &buffer, char *line, ulong line_length,
2332  char *in_string, bool *ml_comment, bool truncated)
2333 {
2334  uchar inchar;
2335  char buff[80], *pos, *out;
2336  COMMANDS *com;
2337  bool need_space= 0;
2338  bool ss_comment= 0;
2339  DBUG_ENTER("add_line");
2340 
2341  if (!line[0] && buffer.is_empty())
2342  DBUG_RETURN(0);
2343 #ifdef HAVE_READLINE
2344  if (status.add_to_history && line[0] && not_in_history(line))
2345  add_filtered_history(line);
2346 #endif
2347  char *end_of_line= line + line_length;
2348 
2349  for (pos= out= line; pos < end_of_line; pos++)
2350  {
2351  inchar= (uchar) *pos;
2352  if (!preserve_comments)
2353  {
2354  // Skip spaces at the beginning of a statement
2355  if (my_isspace(charset_info,inchar) && (out == line) &&
2356  buffer.is_empty())
2357  continue;
2358  }
2359 
2360 #ifdef USE_MB
2361  // Accept multi-byte characters as-is
2362  int length;
2363  if (use_mb(charset_info) &&
2364  (length= my_ismbchar(charset_info, pos, end_of_line)))
2365  {
2366  if (!*ml_comment || preserve_comments)
2367  {
2368  while (length--)
2369  *out++ = *pos++;
2370  pos--;
2371  }
2372  else
2373  pos+= length - 1;
2374  continue;
2375  }
2376 #endif
2377  if (!*ml_comment && inchar == '\\' &&
2378  !(*in_string &&
2379  (mysql.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)))
2380  {
2381  // Found possbile one character command like \c
2382 
2383  if (!(inchar = (uchar) *++pos))
2384  break; // readline adds one '\'
2385  if (*in_string || inchar == 'N') // \N is short for NULL
2386  { // Don't allow commands in string
2387  *out++='\\';
2388  *out++= (char) inchar;
2389  continue;
2390  }
2391  if ((com= find_command((char) inchar)))
2392  {
2393  // Flush previously accepted characters
2394  if (out != line)
2395  {
2396  buffer.append(line, (uint) (out-line));
2397  out= line;
2398  }
2399 
2400  if ((*com->func)(&buffer,pos-1) > 0)
2401  DBUG_RETURN(1); // Quit
2402  if (com->takes_params)
2403  {
2404  if (ss_comment)
2405  {
2406  /*
2407  If a client-side macro appears inside a server-side comment,
2408  discard all characters in the comment after the macro (that is,
2409  until the end of the comment rather than the next delimiter)
2410  */
2411  for (pos++; *pos && (*pos != '*' || *(pos + 1) != '/'); pos++)
2412  ;
2413  pos--;
2414  }
2415  else
2416  {
2417  for (pos++ ;
2418  *pos && (*pos != *delimiter ||
2419  !is_prefix(pos + 1, delimiter + 1)) ; pos++)
2420  ; // Remove parameters
2421  if (!*pos)
2422  pos--;
2423  else
2424  pos+= delimiter_length - 1; // Point at last delim char
2425  }
2426  }
2427  }
2428  else
2429  {
2430  sprintf(buff,"Unknown command '\\%c'.",inchar);
2431  if (put_info(buff,INFO_ERROR) > 0)
2432  DBUG_RETURN(1);
2433  *out++='\\';
2434  *out++=(char) inchar;
2435  continue;
2436  }
2437  }
2438  else if (!*ml_comment && !*in_string && is_prefix(pos, delimiter))
2439  {
2440  // Found a statement. Continue parsing after the delimiter
2441  pos+= delimiter_length;
2442 
2443  if (preserve_comments)
2444  {
2445  while (my_isspace(charset_info, *pos))
2446  *out++= *pos++;
2447  }
2448  // Flush previously accepted characters
2449  if (out != line)
2450  {
2451  buffer.append(line, (uint32) (out-line));
2452  out= line;
2453  }
2454 
2455  if (preserve_comments && ((*pos == '#') ||
2456  ((*pos == '-') &&
2457  (pos[1] == '-') &&
2458  my_isspace(charset_info, pos[2]))))
2459  {
2460  // Add trailing single line comments to this statement
2461  buffer.append(pos);
2462  pos+= strlen(pos);
2463  }
2464 
2465  pos--;
2466 
2467  if ((com= find_command(buffer.c_ptr())))
2468  {
2469 
2470  if ((*com->func)(&buffer, buffer.c_ptr()) > 0)
2471  DBUG_RETURN(1); // Quit
2472  }
2473  else
2474  {
2475  if (com_go(&buffer, 0) > 0) // < 0 is not fatal
2476  DBUG_RETURN(1);
2477  }
2478  buffer.length(0);
2479  }
2480  else if (!*ml_comment && (!*in_string && (inchar == '#' ||
2481  (inchar == '-' && pos[1] == '-' &&
2482  /*
2483  The third byte is either whitespace or is the
2484  end of the line -- which would occur only
2485  because of the user sending newline -- which is
2486  itself whitespace and should also match.
2487  */
2488  (my_isspace(charset_info,pos[2]) ||
2489  !pos[2])))))
2490  {
2491  // Flush previously accepted characters
2492  if (out != line)
2493  {
2494  buffer.append(line, (uint32) (out - line));
2495  out= line;
2496  }
2497 
2498  // comment to end of line
2499  if (preserve_comments)
2500  {
2501  bool started_with_nothing= !buffer.length();
2502 
2503  buffer.append(pos);
2504 
2505  /*
2506  A single-line comment by itself gets sent immediately so that
2507  client commands (delimiter, status, etc) will be interpreted on
2508  the next line.
2509  */
2510  if (started_with_nothing)
2511  {
2512  if (com_go(&buffer, 0) > 0) // < 0 is not fatal
2513  DBUG_RETURN(1);
2514  buffer.length(0);
2515  }
2516  }
2517 
2518  break;
2519  }
2520  else if (!*in_string && inchar == '/' && *(pos+1) == '*' &&
2521  *(pos+2) != '!')
2522  {
2523  if (preserve_comments)
2524  {
2525  *out++= *pos++; // copy '/'
2526  *out++= *pos; // copy '*'
2527  }
2528  else
2529  pos++;
2530  *ml_comment= 1;
2531  if (out != line)
2532  {
2533  buffer.append(line,(uint) (out-line));
2534  out=line;
2535  }
2536  }
2537  else if (*ml_comment && !ss_comment && inchar == '*' && *(pos + 1) == '/')
2538  {
2539  if (preserve_comments)
2540  {
2541  *out++= *pos++; // copy '*'
2542  *out++= *pos; // copy '/'
2543  }
2544  else
2545  pos++;
2546  *ml_comment= 0;
2547  if (out != line)
2548  {
2549  buffer.append(line, (uint32) (out - line));
2550  out= line;
2551  }
2552  // Consumed a 2 chars or more, and will add 1 at most,
2553  // so using the 'line' buffer to edit data in place is ok.
2554  need_space= 1;
2555  }
2556  else
2557  { // Add found char to buffer
2558  if (!*in_string && inchar == '/' && *(pos + 1) == '*' &&
2559  *(pos + 2) == '!')
2560  ss_comment= 1;
2561  else if (!*in_string && ss_comment && inchar == '*' && *(pos + 1) == '/')
2562  ss_comment= 0;
2563  if (inchar == *in_string)
2564  *in_string= 0;
2565  else if (!*ml_comment && !*in_string &&
2566  (inchar == '\'' || inchar == '"' || inchar == '`'))
2567  *in_string= (char) inchar;
2568  if (!*ml_comment || preserve_comments)
2569  {
2570  if (need_space && !my_isspace(charset_info, (char)inchar))
2571  *out++= ' ';
2572  need_space= 0;
2573  *out++= (char) inchar;
2574  }
2575  }
2576  }
2577  if (out != line || !buffer.is_empty())
2578  {
2579  uint length=(uint) (out-line);
2580 
2581  if (!truncated && (!is_delimiter_command(line, length) ||
2582  (*in_string || *ml_comment)))
2583  {
2584  /*
2585  Don't add a new line in case there's a DELIMITER command to be
2586  added to the glob buffer (e.g. on processing a line like
2587  "<command>;DELIMITER <non-eof>") : similar to how a new line is
2588  not added in the case when the DELIMITER is the first command
2589  entered with an empty glob buffer. However, if the delimiter is
2590  part of a string or a comment, the new line should be added. (e.g.
2591  SELECT '\ndelimiter\n';\n)
2592  */
2593  *out++='\n';
2594  length++;
2595  }
2596  if (buffer.length() + length >= buffer.alloced_length())
2597  buffer.realloc(buffer.length()+length+IO_SIZE);
2598  if ((!*ml_comment || preserve_comments) && buffer.append(line, length))
2599  DBUG_RETURN(1);
2600  }
2601  DBUG_RETURN(0);
2602 }
2603 
2604 /*****************************************************************
2605  Interface to Readline Completion
2606 ******************************************************************/
2607 
2608 #ifdef HAVE_READLINE
2609 
2610 C_MODE_START
2611 static char *new_command_generator(const char *text, int);
2612 static char **new_mysql_completion(const char *text, int start, int end);
2613 C_MODE_END
2614 
2615 /*
2616  Tell the GNU Readline library how to complete. We want to try to complete
2617  on command names if this is the first word in the line, or on filenames
2618  if not.
2619 */
2620 
2621 #if defined(USE_NEW_READLINE_INTERFACE)
2622 static int fake_magic_space(int, int);
2623 extern "C" char *no_completion(const char*,int)
2624 #elif defined(USE_LIBEDIT_INTERFACE)
2625 static int fake_magic_space(const char *, int);
2626 extern "C" int no_completion(const char*,int)
2627 #else
2628 extern "C" char *no_completion()
2629 #endif
2630 {
2631  return 0; /* No filename completion */
2632 }
2633 
2634 /* glues pieces of history back together if in pieces */
2635 static void fix_history(String *final_command)
2636 {
2637  int total_lines = 1;
2638  char *ptr = final_command->c_ptr();
2639  String fixed_buffer; /* Converted buffer */
2640  char str_char = '\0'; /* Character if we are in a string or not */
2641 
2642  /* find out how many lines we have and remove newlines */
2643  while (*ptr != '\0')
2644  {
2645  switch (*ptr) {
2646  /* string character */
2647  case '"':
2648  case '\'':
2649  case '`':
2650  if (str_char == '\0') /* open string */
2651  str_char = *ptr;
2652  else if (str_char == *ptr) /* close string */
2653  str_char = '\0';
2654  fixed_buffer.append(ptr,1);
2655  break;
2656  case '\n':
2657  /*
2658  not in string, change to space
2659  if in string, leave it alone
2660  */
2661  fixed_buffer.append(str_char == '\0' ? " " : "\n");
2662  total_lines++;
2663  break;
2664  case '\\':
2665  fixed_buffer.append('\\');
2666  /* need to see if the backslash is escaping anything */
2667  if (str_char)
2668  {
2669  ptr++;
2670  /* special characters that need escaping */
2671  if (*ptr == '\'' || *ptr == '"' || *ptr == '\\')
2672  fixed_buffer.append(ptr,1);
2673  else
2674  ptr--;
2675  }
2676  break;
2677 
2678  default:
2679  fixed_buffer.append(ptr,1);
2680  }
2681  ptr++;
2682  }
2683  if (total_lines > 1)
2684  add_filtered_history(fixed_buffer.ptr());
2685 }
2686 
2687 /*
2688  returns 0 if line matches the previous history entry
2689  returns 1 if the line doesn't match the previous history entry
2690 */
2691 static int not_in_history(const char *line)
2692 {
2693  HIST_ENTRY *oldhist = history_get(history_length);
2694 
2695  if (oldhist == 0)
2696  return 1;
2697  if (strcmp(oldhist->line,line) == 0)
2698  return 0;
2699  return 1;
2700 }
2701 
2702 
2703 #if defined(USE_NEW_READLINE_INTERFACE)
2704 static int fake_magic_space(int, int)
2705 #else
2706 static int fake_magic_space(const char *, int)
2707 #endif
2708 {
2709  rl_insert(1, ' ');
2710  return 0;
2711 }
2712 
2713 
2714 static void initialize_readline (char *name)
2715 {
2716  /* Allow conditional parsing of the ~/.inputrc file. */
2717  rl_readline_name = name;
2718 
2719  /* Tell the completer that we want a crack first. */
2720 #if defined(USE_NEW_READLINE_INTERFACE)
2721  rl_attempted_completion_function= (rl_completion_func_t*)&new_mysql_completion;
2722  rl_completion_entry_function= (rl_compentry_func_t*)&no_completion;
2723 
2724  rl_add_defun("magic-space", (rl_command_func_t *)&fake_magic_space, -1);
2725 #elif defined(USE_LIBEDIT_INTERFACE)
2726 #ifdef HAVE_LOCALE_H
2727  setlocale(LC_ALL,""); /* so as libedit use isprint */
2728 #endif
2729  rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion;
2730  rl_completion_entry_function= &no_completion;
2731  rl_add_defun("magic-space", (Function*)&fake_magic_space, -1);
2732 #else
2733  rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion;
2734  rl_completion_entry_function= &no_completion;
2735 #endif
2736 }
2737 
2738 /*
2739  Attempt to complete on the contents of TEXT. START and END show the
2740  region of TEXT that contains the word to complete. We can use the
2741  entire line in case we want to do some simple parsing. Return the
2742  array of matches, or NULL if there aren't any.
2743 */
2744 
2745 static char **new_mysql_completion(const char *text,
2746  int start __attribute__((unused)),
2747  int end __attribute__((unused)))
2748 {
2749  if (!status.batch && !quick)
2750 #if defined(USE_NEW_READLINE_INTERFACE)
2751  return rl_completion_matches(text, new_command_generator);
2752 #else
2753  return completion_matches((char *)text, (CPFunction *)new_command_generator);
2754 #endif
2755  else
2756  return (char**) 0;
2757 }
2758 
2759 static char *new_command_generator(const char *text,int state)
2760 {
2761  static int textlen;
2762  char *ptr;
2763  static Bucket *b;
2764  static entry *e;
2765  static uint i;
2766 
2767  if (!state)
2768  textlen=(uint) strlen(text);
2769 
2770  if (textlen>0)
2771  { /* lookup in the hash */
2772  if (!state)
2773  {
2774  uint len;
2775 
2776  b = find_all_matches(&ht,text,(uint) strlen(text),&len);
2777  if (!b)
2778  return NullS;
2779  e = b->pData;
2780  }
2781 
2782  if (e)
2783  {
2784  ptr= strdup(e->str);
2785  e = e->pNext;
2786  return ptr;
2787  }
2788  }
2789  else
2790  { /* traverse the entire hash, ugly but works */
2791 
2792  if (!state)
2793  {
2794  /* find the first used bucket */
2795  for (i=0 ; i < ht.nTableSize ; i++)
2796  {
2797  if (ht.arBuckets[i])
2798  {
2799  b = ht.arBuckets[i];
2800  e = b->pData;
2801  break;
2802  }
2803  }
2804  }
2805  ptr= NullS;
2806  while (e && !ptr)
2807  { /* find valid entry in bucket */
2808  if ((uint) strlen(e->str) == b->nKeyLength)
2809  ptr = strdup(e->str);
2810  /* find the next used entry */
2811  e = e->pNext;
2812  if (!e)
2813  { /* find the next used bucket */
2814  b = b->pNext;
2815  if (!b)
2816  {
2817  for (i++ ; i<ht.nTableSize; i++)
2818  {
2819  if (ht.arBuckets[i])
2820  {
2821  b = ht.arBuckets[i];
2822  e = b->pData;
2823  break;
2824  }
2825  }
2826  }
2827  else
2828  e = b->pData;
2829  }
2830  }
2831  if (ptr)
2832  return ptr;
2833  }
2834  return NullS;
2835 }
2836 
2837 
2838 /* Build up the completion hash */
2839 
2840 static void build_completion_hash(bool rehash, bool write_info)
2841 {
2842  COMMANDS *cmd=commands;
2843  MYSQL_RES *databases=0,*tables=0;
2844  MYSQL_RES *fields;
2845  static char ***field_names= 0;
2846  MYSQL_ROW database_row,table_row;
2847  MYSQL_FIELD *sql_field;
2848  char buf[NAME_LEN*2+2]; // table name plus field name plus 2
2849  int i,j,num_fields;
2850  DBUG_ENTER("build_completion_hash");
2851 
2852  if (status.batch || quick || !current_db)
2853  DBUG_VOID_RETURN; // We don't need completion in batches
2854  if (!rehash)
2855  DBUG_VOID_RETURN;
2856 
2857  /* Free old used memory */
2858  if (field_names)
2859  field_names=0;
2860  completion_hash_clean(&ht);
2861  free_root(&hash_mem_root,MYF(0));
2862 
2863  /* hash this file's known subset of SQL commands */
2864  while (cmd->name) {
2865  add_word(&ht,(char*) cmd->name);
2866  cmd++;
2867  }
2868 
2869  /* hash MySQL functions (to be implemented) */
2870 
2871  /* hash all database names */
2872  if (mysql_query(&mysql,"show databases") == 0)
2873  {
2874  if (!(databases = mysql_store_result(&mysql)))
2875  put_info(mysql_error(&mysql),INFO_INFO);
2876  else
2877  {
2878  while ((database_row=mysql_fetch_row(databases)))
2879  {
2880  char *str=strdup_root(&hash_mem_root, (char*) database_row[0]);
2881  if (str)
2882  add_word(&ht,(char*) str);
2883  }
2884  mysql_free_result(databases);
2885  }
2886  }
2887  /* hash all table names */
2888  if (mysql_query(&mysql,"show tables")==0)
2889  {
2890  if (!(tables = mysql_store_result(&mysql)))
2891  put_info(mysql_error(&mysql),INFO_INFO);
2892  else
2893  {
2894  if (mysql_num_rows(tables) > 0 && !opt_silent && write_info)
2895  {
2896  tee_fprintf(stdout, "\
2897 Reading table information for completion of table and column names\n\
2898 You can turn off this feature to get a quicker startup with -A\n\n");
2899  }
2900  while ((table_row=mysql_fetch_row(tables)))
2901  {
2902  char *str=strdup_root(&hash_mem_root, (char*) table_row[0]);
2903  if (str &&
2904  !completion_hash_exists(&ht,(char*) str, (uint) strlen(str)))
2905  add_word(&ht,str);
2906  }
2907  }
2908  }
2909 
2910  /* hash all field names, both with the table prefix and without it */
2911  if (!tables) /* no tables */
2912  {
2913  DBUG_VOID_RETURN;
2914  }
2915  mysql_data_seek(tables,0);
2916  if (!(field_names= (char ***) alloc_root(&hash_mem_root,sizeof(char **) *
2917  (uint) (mysql_num_rows(tables)+1))))
2918  {
2919  mysql_free_result(tables);
2920  DBUG_VOID_RETURN;
2921  }
2922  i=0;
2923  while ((table_row=mysql_fetch_row(tables)))
2924  {
2925  if ((fields=mysql_list_fields(&mysql,(const char*) table_row[0],NullS)))
2926  {
2927  num_fields=mysql_num_fields(fields);
2928  if (!(field_names[i] = (char **) alloc_root(&hash_mem_root,
2929  sizeof(char *) *
2930  (num_fields*2+1))))
2931  {
2932  mysql_free_result(fields);
2933  break;
2934  }
2935  field_names[i][num_fields*2]= NULL;
2936  j=0;
2937  while ((sql_field=mysql_fetch_field(fields)))
2938  {
2939  sprintf(buf,"%.64s.%.64s",table_row[0],sql_field->name);
2940  field_names[i][j] = strdup_root(&hash_mem_root,buf);
2941  add_word(&ht,field_names[i][j]);
2942  field_names[i][num_fields+j] = strdup_root(&hash_mem_root,
2943  sql_field->name);
2944  if (!completion_hash_exists(&ht,field_names[i][num_fields+j],
2945  (uint) strlen(field_names[i][num_fields+j])))
2946  add_word(&ht,field_names[i][num_fields+j]);
2947  j++;
2948  }
2949  mysql_free_result(fields);
2950  }
2951  else
2952  field_names[i]= 0;
2953 
2954  i++;
2955  }
2956  mysql_free_result(tables);
2957  field_names[i]=0; // End pointer
2958  DBUG_VOID_RETURN;
2959 }
2960 
2961  /* for gnu readline */
2962 
2963 #ifndef HAVE_INDEX
2964 extern "C" {
2965 extern char *index(const char *,int c),*rindex(const char *,int);
2966 
2967 char *index(const char *s,int c)
2968 {
2969  for (;;)
2970  {
2971  if (*s == (char) c) return (char*) s;
2972  if (!*s++) return NullS;
2973  }
2974 }
2975 
2976 char *rindex(const char *s,int c)
2977 {
2978  reg3 char *t;
2979 
2980  t = NullS;
2981  do if (*s == (char) c) t = (char*) s; while (*s++);
2982  return (char*) t;
2983 }
2984 }
2985 #endif
2986 
2987 /* Add the given line to mysql history. */
2988 static void add_filtered_history(const char *string)
2989 {
2990  if (!check_histignore(string))
2991  add_history(string);
2992 }
2993 
2994 
3006 static
3007 my_bool check_histignore(const char *string)
3008 {
3009  uint i;
3010  int rc;
3011 
3012  LEX_STRING *tmp;
3013 
3014  DBUG_ENTER("check_histignore");
3015 
3016  for (i= 0; i < histignore_patterns.elements; i++)
3017  {
3018  tmp= dynamic_element(&histignore_patterns, i, LEX_STRING *);
3019  if ((rc= charset_info->coll->wildcmp(charset_info,
3020  string, string + strlen(string),
3021  tmp->str, tmp->str + tmp->length,
3022  wild_prefix, wild_one,
3023  wild_many)) == 0)
3024  DBUG_RETURN(1);
3025  }
3026  DBUG_RETURN(0);
3027 }
3028 
3029 
3038 static
3039 my_bool parse_histignore()
3040 {
3041  LEX_STRING pattern;
3042 
3043  char *token;
3044  const char *search= ":";
3045 
3046  DBUG_ENTER("parse_histignore");
3047 
3048  if (init_hist_patterns())
3049  DBUG_RETURN(1);
3050 
3051  token= strtok(histignore_buffer.str, search);
3052 
3053  while(token != NULL)
3054  {
3055  pattern.str= token;
3056  pattern.length= strlen(pattern.str);
3057  insert_dynamic(&histignore_patterns, &pattern);
3058  token= strtok(NULL, search);
3059  }
3060  DBUG_RETURN(0);
3061 }
3062 
3063 static
3064 my_bool init_hist_patterns()
3065 {
3066  return my_init_dynamic_array(&histignore_patterns,
3067  sizeof(LEX_STRING), 50, 50);
3068 }
3069 
3070 static
3071 void free_hist_patterns()
3072 {
3073  delete_dynamic(&histignore_patterns);
3074 }
3075 #endif /* HAVE_READLINE */
3076 
3077 
3078 static int reconnect(void)
3079 {
3080  /* purecov: begin tested */
3081  if (opt_reconnect)
3082  {
3083  put_info("No connection. Trying to reconnect...",INFO_INFO);
3084  (void) com_connect((String *) 0, 0);
3085  if (opt_rehash)
3086  com_rehash(NULL, NULL);
3087  }
3088  if (!connected)
3089  return put_info("Can't connect to the server\n",INFO_ERROR);
3090  /* purecov: end */
3091  return 0;
3092 }
3093 
3094 static void get_current_db()
3095 {
3096  MYSQL_RES *res;
3097 
3098  /* If one_database is set, current_db is not supposed to change. */
3099  if (one_database)
3100  return;
3101 
3102  my_free(current_db);
3103  current_db= NULL;
3104  /* In case of error below current_db will be NULL */
3105  if (!mysql_query(&mysql, "SELECT DATABASE()") &&
3106  (res= mysql_use_result(&mysql)))
3107  {
3108  MYSQL_ROW row= mysql_fetch_row(res);
3109  if (row && row[0])
3110  current_db= my_strdup(row[0], MYF(MY_WME));
3111  mysql_free_result(res);
3112  }
3113 }
3114 
3115 /***************************************************************************
3116  The different commands
3117 ***************************************************************************/
3118 
3119 int mysql_real_query_for_lazy(const char *buf, int length)
3120 {
3121  for (uint retry=0;; retry++)
3122  {
3123  int error;
3124  if (!mysql_real_query(&mysql,buf,length))
3125  return 0;
3126  error= put_error(&mysql);
3127  if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 ||
3128  !opt_reconnect)
3129  return error;
3130  if (reconnect())
3131  return error;
3132  }
3133 }
3134 
3135 int mysql_store_result_for_lazy(MYSQL_RES **result)
3136 {
3137  if ((*result=mysql_store_result(&mysql)))
3138  return 0;
3139 
3140  if (mysql_error(&mysql)[0])
3141  return put_error(&mysql);
3142  return 0;
3143 }
3144 
3145 static void print_help_item(MYSQL_ROW *cur, int num_name, int num_cat, char *last_char)
3146 {
3147  char ccat= (*cur)[num_cat][0];
3148  if (*last_char != ccat)
3149  {
3150  put_info(ccat == 'Y' ? "categories:" : "topics:", INFO_INFO);
3151  *last_char= ccat;
3152  }
3153  tee_fprintf(PAGER, " %s\n", (*cur)[num_name]);
3154 }
3155 
3156 
3157 static int com_server_help(String *buffer __attribute__((unused)),
3158  char *line __attribute__((unused)), char *help_arg)
3159 {
3160  MYSQL_ROW cur;
3161  const char *server_cmd;
3162  char cmd_buf[100 + 1];
3163  MYSQL_RES *result;
3164  int error;
3165 
3166  if (help_arg[0] != '\'')
3167  {
3168  char *end_arg= strend(help_arg);
3169  if(--end_arg)
3170  {
3171  while (my_isspace(charset_info,*end_arg))
3172  end_arg--;
3173  *++end_arg= '\0';
3174  }
3175  (void) strxnmov(cmd_buf, sizeof(cmd_buf), "help '", help_arg, "'", NullS);
3176  }
3177  else
3178  (void) strxnmov(cmd_buf, sizeof(cmd_buf), "help ", help_arg, NullS);
3179 
3180  server_cmd= cmd_buf;
3181 
3182  if (!status.batch)
3183  {
3184  old_buffer= *buffer;
3185  old_buffer.copy();
3186  }
3187 
3188  if (!connected && reconnect())
3189  return 1;
3190 
3191  if ((error= mysql_real_query_for_lazy(server_cmd,(int)strlen(server_cmd))) ||
3192  (error= mysql_store_result_for_lazy(&result)))
3193  return error;
3194 
3195  if (result)
3196  {
3197  unsigned int num_fields= mysql_num_fields(result);
3198  my_ulonglong num_rows= mysql_num_rows(result);
3199  mysql_fetch_fields(result);
3200  if (num_fields==3 && num_rows==1)
3201  {
3202  if (!(cur= mysql_fetch_row(result)))
3203  {
3204  error= -1;
3205  goto err;
3206  }
3207 
3208  init_pager();
3209  tee_fprintf(PAGER, "Name: \'%s\'\n", cur[0]);
3210  tee_fprintf(PAGER, "Description:\n%s", cur[1]);
3211  if (cur[2] && *((char*)cur[2]))
3212  tee_fprintf(PAGER, "Examples:\n%s", cur[2]);
3213  tee_fprintf(PAGER, "\n");
3214  end_pager();
3215  }
3216  else if (num_fields >= 2 && num_rows)
3217  {
3218  init_pager();
3219  char last_char= 0;
3220 
3221  int num_name= 0, num_cat= 0;
3222  LINT_INIT(num_name);
3223  LINT_INIT(num_cat);
3224 
3225  if (num_fields == 2)
3226  {
3227  put_info("Many help items for your request exist.", INFO_INFO);
3228  put_info("To make a more specific request, please type 'help <item>',\nwhere <item> is one of the following", INFO_INFO);
3229  num_name= 0;
3230  num_cat= 1;
3231  }
3232  else if ((cur= mysql_fetch_row(result)))
3233  {
3234  tee_fprintf(PAGER, "You asked for help about help category: \"%s\"\n", cur[0]);
3235  put_info("For more information, type 'help <item>', where <item> is one of the following", INFO_INFO);
3236  num_name= 1;
3237  num_cat= 2;
3238  print_help_item(&cur,1,2,&last_char);
3239  }
3240 
3241  while ((cur= mysql_fetch_row(result)))
3242  print_help_item(&cur,num_name,num_cat,&last_char);
3243  tee_fprintf(PAGER, "\n");
3244  end_pager();
3245  }
3246  else
3247  {
3248  put_info("\nNothing found", INFO_INFO);
3249  if (strncasecmp(server_cmd, "help 'contents'", 15) == 0)
3250  {
3251  put_info("\nPlease check if 'help tables' are loaded.\n", INFO_INFO);
3252  goto err;
3253  }
3254  put_info("Please try to run 'help contents' for a list of all accessible topics\n", INFO_INFO);
3255  }
3256  }
3257 
3258 err:
3259  mysql_free_result(result);
3260  return error;
3261 }
3262 
3263 static int
3264 com_help(String *buffer __attribute__((unused)),
3265  char *line __attribute__((unused)))
3266 {
3267  reg1 int i, j;
3268  char * help_arg= strchr(line,' '), buff[32], *end;
3269  if (help_arg)
3270  {
3271  while (my_isspace(charset_info,*help_arg))
3272  help_arg++;
3273  if (*help_arg)
3274  return com_server_help(buffer,line,help_arg);
3275  }
3276 
3277  put_info("\nFor information about MySQL products and services, visit:\n"
3278  " http://www.mysql.com/\n"
3279  "For developer information, including the MySQL Reference Manual, "
3280  "visit:\n"
3281  " http://dev.mysql.com/\n"
3282  "To buy MySQL Enterprise support, training, or other products, visit:\n"
3283  " https://shop.mysql.com/\n", INFO_INFO);
3284  put_info("List of all MySQL commands:", INFO_INFO);
3285  if (!named_cmds)
3286  put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO);
3287  for (i = 0; commands[i].name; i++)
3288  {
3289  end= strmov(buff, commands[i].name);
3290  for (j= (int)strlen(commands[i].name); j < 10; j++)
3291  end= strmov(end, " ");
3292  if (commands[i].func)
3293  tee_fprintf(stdout, "%s(\\%c) %s\n", buff,
3294  commands[i].cmd_char, commands[i].doc);
3295  }
3296  if (connected && mysql_get_server_version(&mysql) >= 40100)
3297  put_info("\nFor server side help, type 'help contents'\n", INFO_INFO);
3298  return 0;
3299 }
3300 
3301 
3302  /* ARGSUSED */
3303 static int
3304 com_clear(String *buffer,char *line __attribute__((unused)))
3305 {
3306 #ifdef HAVE_READLINE
3307  if (status.add_to_history)
3308  fix_history(buffer);
3309 #endif
3310  buffer->length(0);
3311  return 0;
3312 }
3313 
3314  /* ARGSUSED */
3315 static int
3316 com_charset(String *buffer __attribute__((unused)), char *line)
3317 {
3318  char buff[256], *param;
3319  const CHARSET_INFO *new_cs;
3320  strmake(buff, line, sizeof(buff) - 1);
3321  param= get_arg(buff, 0);
3322  if (!param || !*param)
3323  {
3324  return put_info("Usage: \\C charset_name | charset charset_name",
3325  INFO_ERROR, 0);
3326  }
3327  new_cs= get_charset_by_csname(param, MY_CS_PRIMARY, MYF(MY_WME));
3328  if (new_cs)
3329  {
3330  charset_info= new_cs;
3331  mysql_set_character_set(&mysql, charset_info->csname);
3332  default_charset= (char *)charset_info->csname;
3333  put_info("Charset changed", INFO_INFO);
3334  }
3335  else put_info("Charset is not found", INFO_INFO);
3336  return 0;
3337 }
3338 
3339 /*
3340  Execute command
3341  Returns: 0 if ok
3342  -1 if not fatal error
3343  1 if fatal error
3344 */
3345 
3346 
3347 static int
3348 com_go(String *buffer,char *line __attribute__((unused)))
3349 {
3350  char buff[200]; /* about 110 chars used so far */
3351  char time_buff[52+3+1]; /* time max + space&parens + NUL */
3352  MYSQL_RES *result;
3353  ulong timer, warnings= 0;
3354  uint error= 0;
3355  int err= 0;
3356 
3357  interrupted_query= 0;
3358  if (!status.batch)
3359  {
3360  old_buffer= *buffer; // Save for edit command
3361  old_buffer.copy();
3362  }
3363 
3364  /* Remove garbage for nicer messages */
3365  LINT_INIT(buff[0]);
3366  remove_cntrl(*buffer);
3367 
3368  if (buffer->is_empty())
3369  {
3370  if (status.batch) // Ignore empty quries
3371  return 0;
3372  return put_info("No query specified\n",INFO_ERROR);
3373 
3374  }
3375  if (!connected && reconnect())
3376  {
3377  buffer->length(0); // Remove query on error
3378  return opt_reconnect ? -1 : 1; // Fatal error
3379  }
3380  if (verbose)
3381  (void) com_print(buffer,0);
3382 
3383  if (skip_updates &&
3384  (buffer->length() < 4 || my_strnncoll(charset_info,
3385  (const uchar*)buffer->ptr(),4,
3386  (const uchar*)"SET ",4)))
3387  {
3388  (void) put_info("Ignoring query to other database",INFO_INFO);
3389  return 0;
3390  }
3391 
3392  timer=start_timer();
3393  executing_query= 1;
3394  error= mysql_real_query_for_lazy(buffer->ptr(),buffer->length());
3395 
3396 #ifdef HAVE_READLINE
3397  if (status.add_to_history)
3398  {
3399  buffer->append(vertical ? "\\G" : delimiter);
3400  /* Append final command onto history */
3401  fix_history(buffer);
3402  }
3403 #endif
3404 
3405  buffer->length(0);
3406 
3407  if (error)
3408  goto end;
3409 
3410  do
3411  {
3412  char *pos;
3413  bool batchmode= (status.batch && verbose <= 1) ? TRUE : FALSE;
3414  buff[0]= 0;
3415 
3416  if (quick)
3417  {
3418  if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql))
3419  {
3420  error= put_error(&mysql);
3421  goto end;
3422  }
3423  }
3424  else
3425  {
3426  error= mysql_store_result_for_lazy(&result);
3427  if (error)
3428  goto end;
3429  }
3430 
3431  if (verbose >= 3 || !opt_silent)
3432  mysql_end_timer(timer,time_buff);
3433  else
3434  time_buff[0]= '\0';
3435 
3436  /* Every branch must truncate buff . */
3437  if (result)
3438  {
3439  if (!mysql_num_rows(result) && ! quick && !column_types_flag)
3440  {
3441  strmov(buff, "Empty set");
3442  if (opt_xml)
3443  {
3444  /*
3445  We must print XML header and footer
3446  to produce a well-formed XML even if
3447  the result set is empty (Bug#27608).
3448  */
3449  init_pager();
3450  print_table_data_xml(result);
3451  end_pager();
3452  }
3453  }
3454  else
3455  {
3456  init_pager();
3457  if (opt_html)
3458  print_table_data_html(result);
3459  else if (opt_xml)
3460  print_table_data_xml(result);
3461  else if (vertical || (auto_vertical_output && (terminal_width < get_result_width(result))))
3462  print_table_data_vertically(result);
3463  else if (opt_silent && verbose <= 2 && !output_tables)
3464  print_tab_data(result);
3465  else
3466  print_table_data(result);
3467  if( !batchmode )
3468  sprintf(buff,"%lld %s in set",
3469  mysql_num_rows(result),
3470  mysql_num_rows(result) == 1LL ? "row" : "rows");
3471  end_pager();
3472  if (mysql_errno(&mysql))
3473  error= put_error(&mysql);
3474  }
3475  }
3476  else if (mysql_affected_rows(&mysql) == ~(ulonglong) 0)
3477  strmov(buff,"Query OK");
3478  else if( !batchmode )
3479  sprintf(buff,"Query OK, %lld %s affected",
3480  mysql_affected_rows(&mysql),
3481  mysql_affected_rows(&mysql) == 1LL ? "row" : "rows");
3482 
3483  pos=strend(buff);
3484  if ((warnings= mysql_warning_count(&mysql)) && !batchmode)
3485  {
3486  *pos++= ',';
3487  *pos++= ' ';
3488  pos=int10_to_str(warnings, pos, 10);
3489  pos=strmov(pos, " warning");
3490  if (warnings != 1)
3491  *pos++= 's';
3492  }
3493  strmov(pos, time_buff);
3494  put_info(buff,INFO_RESULT);
3495  if (mysql_info(&mysql))
3496  put_info(mysql_info(&mysql),INFO_RESULT);
3497  put_info("",INFO_RESULT); // Empty row
3498 
3499  if (result && !mysql_eof(result)) /* Something wrong when using quick */
3500  error= put_error(&mysql);
3501  else if (unbuffered)
3502  fflush(stdout);
3503  mysql_free_result(result);
3504  } while (!(err= mysql_next_result(&mysql)));
3505  if (err >= 1)
3506  error= put_error(&mysql);
3507 
3508 end:
3509 
3510  /* Show warnings if any or error occured */
3511  if (show_warnings == 1 && (warnings >= 1 || error))
3512  print_warnings();
3513 
3514  if (!error && !status.batch &&
3515  (mysql.server_status & SERVER_STATUS_DB_DROPPED))
3516  get_current_db();
3517 
3518  executing_query= 0;
3519  return error; /* New command follows */
3520 }
3521 
3522 
3523 static void init_pager()
3524 {
3525 #ifdef USE_POPEN
3526  if (!opt_nopager)
3527  {
3528  if (!(PAGER= popen(pager, "w")))
3529  {
3530  tee_fprintf(stdout, "popen() failed! defaulting PAGER to stdout!\n");
3531  PAGER= stdout;
3532  }
3533  }
3534  else
3535 #endif
3536  PAGER= stdout;
3537 }
3538 
3539 static void end_pager()
3540 {
3541 #ifdef USE_POPEN
3542  if (!opt_nopager)
3543  pclose(PAGER);
3544 #endif
3545 }
3546 
3547 
3548 static void init_tee(const char *file_name)
3549 {
3550  FILE* new_outfile;
3551  if (opt_outfile)
3552  end_tee();
3553  if (!(new_outfile= my_fopen(file_name, O_APPEND | O_WRONLY, MYF(MY_WME))))
3554  {
3555  tee_fprintf(stdout, "Error logging to file '%s'\n", file_name);
3556  return;
3557  }
3558  OUTFILE = new_outfile;
3559  strmake(outfile, file_name, FN_REFLEN-1);
3560  tee_fprintf(stdout, "Logging to file '%s'\n", file_name);
3561  opt_outfile= 1;
3562  return;
3563 }
3564 
3565 
3566 static void end_tee()
3567 {
3568  my_fclose(OUTFILE, MYF(0));
3569  OUTFILE= 0;
3570  opt_outfile= 0;
3571  return;
3572 }
3573 
3574 
3575 static int
3576 com_ego(String *buffer,char *line)
3577 {
3578  int result;
3579  bool oldvertical=vertical;
3580  vertical=1;
3581  result=com_go(buffer,line);
3582  vertical=oldvertical;
3583  return result;
3584 }
3585 
3586 
3587 static const char *fieldtype2str(enum enum_field_types type)
3588 {
3589  switch (type) {
3590  case MYSQL_TYPE_BIT: return "BIT";
3591  case MYSQL_TYPE_BLOB: return "BLOB";
3592  case MYSQL_TYPE_DATE: return "DATE";
3593  case MYSQL_TYPE_DATETIME: return "DATETIME";
3594  case MYSQL_TYPE_NEWDECIMAL: return "NEWDECIMAL";
3595  case MYSQL_TYPE_DECIMAL: return "DECIMAL";
3596  case MYSQL_TYPE_DOUBLE: return "DOUBLE";
3597  case MYSQL_TYPE_ENUM: return "ENUM";
3598  case MYSQL_TYPE_FLOAT: return "FLOAT";
3599  case MYSQL_TYPE_GEOMETRY: return "GEOMETRY";
3600  case MYSQL_TYPE_INT24: return "INT24";
3601  case MYSQL_TYPE_LONG: return "LONG";
3602  case MYSQL_TYPE_LONGLONG: return "LONGLONG";
3603  case MYSQL_TYPE_LONG_BLOB: return "LONG_BLOB";
3604  case MYSQL_TYPE_MEDIUM_BLOB: return "MEDIUM_BLOB";
3605  case MYSQL_TYPE_NEWDATE: return "NEWDATE";
3606  case MYSQL_TYPE_NULL: return "NULL";
3607  case MYSQL_TYPE_SET: return "SET";
3608  case MYSQL_TYPE_SHORT: return "SHORT";
3609  case MYSQL_TYPE_STRING: return "STRING";
3610  case MYSQL_TYPE_TIME: return "TIME";
3611  case MYSQL_TYPE_TIMESTAMP: return "TIMESTAMP";
3612  case MYSQL_TYPE_TINY: return "TINY";
3613  case MYSQL_TYPE_TINY_BLOB: return "TINY_BLOB";
3614  case MYSQL_TYPE_VAR_STRING: return "VAR_STRING";
3615  case MYSQL_TYPE_YEAR: return "YEAR";
3616  default: return "?-unknown-?";
3617  }
3618 }
3619 
3620 static char *fieldflags2str(uint f) {
3621  static char buf[1024];
3622  char *s=buf;
3623  *s=0;
3624 #define ff2s_check_flag(X) \
3625  if (f & X ## _FLAG) { s=strmov(s, # X " "); f &= ~ X ## _FLAG; }
3626  ff2s_check_flag(NOT_NULL);
3627  ff2s_check_flag(PRI_KEY);
3628  ff2s_check_flag(UNIQUE_KEY);
3629  ff2s_check_flag(MULTIPLE_KEY);
3630  ff2s_check_flag(BLOB);
3631  ff2s_check_flag(UNSIGNED);
3632  ff2s_check_flag(ZEROFILL);
3633  ff2s_check_flag(BINARY);
3634  ff2s_check_flag(ENUM);
3635  ff2s_check_flag(AUTO_INCREMENT);
3636  ff2s_check_flag(TIMESTAMP);
3637  ff2s_check_flag(SET);
3638  ff2s_check_flag(NO_DEFAULT_VALUE);
3639  ff2s_check_flag(NUM);
3640  ff2s_check_flag(PART_KEY);
3641  ff2s_check_flag(GROUP);
3642  ff2s_check_flag(UNIQUE);
3643  ff2s_check_flag(BINCMP);
3644  ff2s_check_flag(ON_UPDATE_NOW);
3645 #undef ff2s_check_flag
3646  if (f)
3647  sprintf(s, " unknows=0x%04x", f);
3648  return buf;
3649 }
3650 
3651 static void
3652 print_field_types(MYSQL_RES *result)
3653 {
3654  MYSQL_FIELD *field;
3655  uint i=0;
3656 
3657  while ((field = mysql_fetch_field(result)))
3658  {
3659  tee_fprintf(PAGER, "Field %3u: `%s`\n"
3660  "Catalog: `%s`\n"
3661  "Database: `%s`\n"
3662  "Table: `%s`\n"
3663  "Org_table: `%s`\n"
3664  "Type: %s\n"
3665  "Collation: %s (%u)\n"
3666  "Length: %lu\n"
3667  "Max_length: %lu\n"
3668  "Decimals: %u\n"
3669  "Flags: %s\n\n",
3670  ++i,
3671  field->name, field->catalog, field->db, field->table,
3672  field->org_table, fieldtype2str(field->type),
3673  get_charset_name(field->charsetnr), field->charsetnr,
3674  field->length, field->max_length, field->decimals,
3675  fieldflags2str(field->flags));
3676  }
3677  tee_puts("", PAGER);
3678 }
3679 
3680 
3681 static void
3682 print_table_data(MYSQL_RES *result)
3683 {
3684  String separator(256);
3685  MYSQL_ROW cur;
3686  MYSQL_FIELD *field;
3687  bool *num_flag;
3688  size_t sz;
3689 
3690  sz= sizeof(bool) * mysql_num_fields(result);
3691  num_flag= (bool *) my_safe_alloca(sz, MAX_ALLOCA_SIZE);
3692  if (column_types_flag)
3693  {
3694  print_field_types(result);
3695  if (!mysql_num_rows(result))
3696  return;
3697  mysql_field_seek(result,0);
3698  }
3699  separator.copy("+",1,charset_info);
3700  while ((field = mysql_fetch_field(result)))
3701  {
3702  uint length= column_names ? field->name_length : 0;
3703  if (quick)
3704  length= max<size_t>(length, field->length);
3705  else
3706  length= max<size_t>(length, field->max_length);
3707  if (length < 4 && !IS_NOT_NULL(field->flags))
3708  length=4; // Room for "NULL"
3709  field->max_length=length;
3710  separator.fill(separator.length()+length+2,'-');
3711  separator.append('+');
3712  }
3713  separator.append('\0'); // End marker for \0
3714  tee_puts((char*) separator.ptr(), PAGER);
3715  if (column_names)
3716  {
3717  mysql_field_seek(result,0);
3718  (void) tee_fputs("|", PAGER);
3719  for (uint off=0; (field = mysql_fetch_field(result)) ; off++)
3720  {
3721  uint name_length= (uint) strlen(field->name);
3722  uint numcells= charset_info->cset->numcells(charset_info,
3723  field->name,
3724  field->name + name_length);
3725  uint display_length= field->max_length + name_length - numcells;
3726  tee_fprintf(PAGER, " %-*s |",
3727  min<int>(display_length, MAX_COLUMN_LENGTH),
3728  field->name);
3729  num_flag[off]= IS_NUM(field->type);
3730  }
3731  (void) tee_fputs("\n", PAGER);
3732  tee_puts((char*) separator.ptr(), PAGER);
3733  }
3734 
3735  while ((cur= mysql_fetch_row(result)))
3736  {
3737  if (interrupted_query)
3738  break;
3739  ulong *lengths= mysql_fetch_lengths(result);
3740  (void) tee_fputs("| ", PAGER);
3741  mysql_field_seek(result, 0);
3742  for (uint off= 0; off < mysql_num_fields(result); off++)
3743  {
3744  const char *buffer;
3745  uint data_length;
3746  uint field_max_length;
3747  uint visible_length;
3748  uint extra_padding;
3749 
3750  if (off)
3751  (void) tee_fputs(" ", PAGER);
3752 
3753  if (cur[off] == NULL)
3754  {
3755  buffer= "NULL";
3756  data_length= 4;
3757  }
3758  else
3759  {
3760  buffer= cur[off];
3761  data_length= (uint) lengths[off];
3762  }
3763 
3764  field= mysql_fetch_field(result);
3765  field_max_length= field->max_length;
3766 
3767  /*
3768  How many text cells on the screen will this string span? If it contains
3769  multibyte characters, then the number of characters we occupy on screen
3770  will be fewer than the number of bytes we occupy in memory.
3771 
3772  We need to find how much screen real-estate we will occupy to know how
3773  many extra padding-characters we should send with the printing function.
3774  */
3775  visible_length= charset_info->cset->numcells(charset_info, buffer, buffer + data_length);
3776  extra_padding= data_length - visible_length;
3777 
3778  if (field_max_length > MAX_COLUMN_LENGTH)
3779  tee_print_sized_data(buffer, data_length, MAX_COLUMN_LENGTH+extra_padding, FALSE);
3780  else
3781  {
3782  if (num_flag[off] != 0) /* if it is numeric, we right-justify it */
3783  tee_print_sized_data(buffer, data_length, field_max_length+extra_padding, TRUE);
3784  else
3785  tee_print_sized_data(buffer, data_length, field_max_length+extra_padding, FALSE);
3786  }
3787  tee_fputs(" |", PAGER);
3788  }
3789  (void) tee_fputs("\n", PAGER);
3790  }
3791  tee_puts((char*) separator.ptr(), PAGER);
3792  my_safe_afree((bool *) num_flag, sz, MAX_ALLOCA_SIZE);
3793 }
3794 
3811 static int get_field_disp_length(MYSQL_FIELD *field)
3812 {
3813  uint length= column_names ? field->name_length : 0;
3814 
3815  if (quick)
3816  length= max<uint>(length, field->length);
3817  else
3818  length= max<uint>(length, field->max_length);
3819 
3820  if (length < 4 && !IS_NOT_NULL(field->flags))
3821  length= 4; /* Room for "NULL" */
3822 
3823  return length;
3824 }
3825 
3834 static int get_result_width(MYSQL_RES *result)
3835 {
3836  unsigned int len= 0;
3837  MYSQL_FIELD *field;
3838  MYSQL_FIELD_OFFSET offset;
3839 
3840 #ifndef DBUG_OFF
3841  offset= mysql_field_tell(result);
3842  DBUG_ASSERT(offset == 0);
3843 #else
3844  offset= 0;
3845 #endif
3846 
3847  while ((field= mysql_fetch_field(result)) != NULL)
3848  len+= get_field_disp_length(field) + 3; /* plus bar, space, & final space */
3849 
3850  (void) mysql_field_seek(result, offset);
3851 
3852  return len + 1; /* plus final bar. */
3853 }
3854 
3855 static void
3856 tee_print_sized_data(const char *data, unsigned int data_length, unsigned int total_bytes_to_send, bool right_justified)
3857 {
3858  /*
3859  For '\0's print ASCII spaces instead, as '\0' is eaten by (at
3860  least my) console driver, and that messes up the pretty table
3861  grid. (The \0 is also the reason we can't use fprintf() .)
3862  */
3863  unsigned int i;
3864 
3865  if (right_justified)
3866  for (i= data_length; i < total_bytes_to_send; i++)
3867  tee_putc((int)' ', PAGER);
3868 
3869  tee_write(PAGER, data, data_length, MY_PRINT_SPS_0 | MY_PRINT_MB);
3870 
3871  if (! right_justified)
3872  for (i= data_length; i < total_bytes_to_send; i++)
3873  tee_putc((int)' ', PAGER);
3874 }
3875 
3876 
3877 
3878 static void
3879 print_table_data_html(MYSQL_RES *result)
3880 {
3881  MYSQL_ROW cur;
3882  MYSQL_FIELD *field;
3883 
3884  mysql_field_seek(result,0);
3885  (void) tee_fputs("<TABLE BORDER=1><TR>", PAGER);
3886  if (column_names)
3887  {
3888  while((field = mysql_fetch_field(result)))
3889  {
3890  tee_fputs("<TH>", PAGER);
3891  if (field->name && field->name[0])
3892  xmlencode_print(field->name, field->name_length);
3893  else
3894  tee_fputs(field->name ? " &nbsp; " : "NULL", PAGER);
3895  tee_fputs("</TH>", PAGER);
3896  }
3897  (void) tee_fputs("</TR>", PAGER);
3898  }
3899  while ((cur = mysql_fetch_row(result)))
3900  {
3901  if (interrupted_query)
3902  break;
3903  ulong *lengths=mysql_fetch_lengths(result);
3904  (void) tee_fputs("<TR>", PAGER);
3905  for (uint i=0; i < mysql_num_fields(result); i++)
3906  {
3907  (void) tee_fputs("<TD>", PAGER);
3908  xmlencode_print(cur[i], lengths[i]);
3909  (void) tee_fputs("</TD>", PAGER);
3910  }
3911  (void) tee_fputs("</TR>", PAGER);
3912  }
3913  (void) tee_fputs("</TABLE>", PAGER);
3914 }
3915 
3916 
3917 static void
3918 print_table_data_xml(MYSQL_RES *result)
3919 {
3920  MYSQL_ROW cur;
3921  MYSQL_FIELD *fields;
3922 
3923  mysql_field_seek(result,0);
3924 
3925  tee_fputs("<?xml version=\"1.0\"?>\n\n<resultset statement=\"", PAGER);
3926  xmlencode_print(glob_buffer.ptr(), (int)strlen(glob_buffer.ptr()));
3927  tee_fputs("\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">",
3928  PAGER);
3929 
3930  fields = mysql_fetch_fields(result);
3931  while ((cur = mysql_fetch_row(result)))
3932  {
3933  if (interrupted_query)
3934  break;
3935  ulong *lengths=mysql_fetch_lengths(result);
3936  (void) tee_fputs("\n <row>\n", PAGER);
3937  for (uint i=0; i < mysql_num_fields(result); i++)
3938  {
3939  tee_fprintf(PAGER, "\t<field name=\"");
3940  xmlencode_print(fields[i].name, (uint) strlen(fields[i].name));
3941  if (cur[i])
3942  {
3943  tee_fprintf(PAGER, "\">");
3944  xmlencode_print(cur[i], lengths[i]);
3945  tee_fprintf(PAGER, "</field>\n");
3946  }
3947  else
3948  tee_fprintf(PAGER, "\" xsi:nil=\"true\" />\n");
3949  }
3950  (void) tee_fputs(" </row>\n", PAGER);
3951  }
3952  (void) tee_fputs("</resultset>\n", PAGER);
3953 }
3954 
3955 
3956 static void
3957 print_table_data_vertically(MYSQL_RES *result)
3958 {
3959  MYSQL_ROW cur;
3960  uint max_length=0;
3961  MYSQL_FIELD *field;
3962 
3963  while ((field = mysql_fetch_field(result)))
3964  {
3965  uint length= field->name_length;
3966  if (length > max_length)
3967  max_length= length;
3968  field->max_length=length;
3969  }
3970 
3971  mysql_field_seek(result,0);
3972  for (uint row_count=1; (cur= mysql_fetch_row(result)); row_count++)
3973  {
3974  if (interrupted_query)
3975  break;
3976  mysql_field_seek(result,0);
3977  tee_fprintf(PAGER,
3978  "*************************** %d. row ***************************\n", row_count);
3979 
3980  ulong *lengths= mysql_fetch_lengths(result);
3981 
3982  for (uint off=0; off < mysql_num_fields(result); off++)
3983  {
3984  field= mysql_fetch_field(result);
3985  if (column_names)
3986  tee_fprintf(PAGER, "%*s: ",(int) max_length,field->name);
3987  if (cur[off])
3988  {
3989  tee_write(PAGER, cur[off], lengths[off], MY_PRINT_SPS_0 | MY_PRINT_MB);
3990  tee_putc('\n', PAGER);
3991  }
3992  else
3993  tee_fprintf(PAGER, "NULL\n");
3994  }
3995  }
3996 }
3997 
3998 
3999 /* print_warnings should be called right after executing a statement */
4000 
4001 static void print_warnings()
4002 {
4003  const char *query;
4004  MYSQL_RES *result;
4005  MYSQL_ROW cur;
4006  my_ulonglong num_rows;
4007 
4008  /* Save current error before calling "show warnings" */
4009  uint error= mysql_errno(&mysql);
4010 
4011  /* Get the warnings */
4012  query= "show warnings";
4013  mysql_real_query_for_lazy(query, strlen(query));
4014  mysql_store_result_for_lazy(&result);
4015 
4016  /* Bail out when no warnings */
4017  if (!result || !(num_rows= mysql_num_rows(result)))
4018  goto end;
4019 
4020  cur= mysql_fetch_row(result);
4021 
4022  /*
4023  Don't print a duplicate of the current error. It is possible for SHOW
4024  WARNINGS to return multiple errors with the same code, but different
4025  messages. To be safe, skip printing the duplicate only if it is the only
4026  warning.
4027  */
4028  if (!cur || (num_rows == 1 && error == (uint) strtoul(cur[1], NULL, 10)))
4029  goto end;
4030 
4031  /* Print the warnings */
4032  init_pager();
4033  do
4034  {
4035  tee_fprintf(PAGER, "%s (Code %s): %s\n", cur[0], cur[1], cur[2]);
4036  } while ((cur= mysql_fetch_row(result)));
4037  end_pager();
4038 
4039 end:
4040  mysql_free_result(result);
4041 }
4042 
4043 
4044 static const char *array_value(const char **array, char key)
4045 {
4046  for (; *array; array+= 2)
4047  if (**array == key)
4048  return array[1];
4049  return 0;
4050 }
4051 
4052 
4053 static void
4054 xmlencode_print(const char *src, uint length)
4055 {
4056  if (!src)
4057  tee_fputs("NULL", PAGER);
4058  else
4059  tee_write(PAGER, src, length, MY_PRINT_XML | MY_PRINT_MB);
4060 }
4061 
4062 
4063 static void
4064 safe_put_field(const char *pos,ulong length)
4065 {
4066  if (!pos)
4067  tee_fputs("NULL", PAGER);
4068  else
4069  {
4070  int flags= MY_PRINT_MB | (opt_raw_data ? 0 : (MY_PRINT_ESC_0 | MY_PRINT_CTRL));
4071  /* Can't use tee_fputs(), it stops with NUL characters. */
4072  tee_write(PAGER, pos, length, flags);
4073  }
4074 }
4075 
4076 
4077 static void
4078 print_tab_data(MYSQL_RES *result)
4079 {
4080  MYSQL_ROW cur;
4081  MYSQL_FIELD *field;
4082  ulong *lengths;
4083 
4084  if (opt_silent < 2 && column_names)
4085  {
4086  int first=0;
4087  while ((field = mysql_fetch_field(result)))
4088  {
4089  if (first++)
4090  (void) tee_fputs("\t", PAGER);
4091  (void) tee_fputs(field->name, PAGER);
4092  }
4093  (void) tee_fputs("\n", PAGER);
4094  }
4095  while ((cur = mysql_fetch_row(result)))
4096  {
4097  lengths=mysql_fetch_lengths(result);
4098  safe_put_field(cur[0],lengths[0]);
4099  for (uint off=1 ; off < mysql_num_fields(result); off++)
4100  {
4101  (void) tee_fputs("\t", PAGER);
4102  safe_put_field(cur[off], lengths[off]);
4103  }
4104  (void) tee_fputs("\n", PAGER);
4105  }
4106 }
4107 
4108 static int
4109 com_tee(String *buffer __attribute__((unused)),
4110  char *line __attribute__((unused)))
4111 {
4112  char file_name[FN_REFLEN], *end, *param;
4113 
4114  while (my_isspace(charset_info,*line))
4115  line++;
4116  if (!(param = strchr(line, ' '))) // if outfile wasn't given, use the default
4117  {
4118  if (!strlen(outfile))
4119  {
4120  printf("No previous outfile available, you must give a filename!\n");
4121  return 0;
4122  }
4123  else if (opt_outfile)
4124  {
4125  tee_fprintf(stdout, "Currently logging to file '%s'\n", outfile);
4126  return 0;
4127  }
4128  else
4129  param = outfile; //resume using the old outfile
4130  }
4131 
4132  /* eliminate the spaces before the parameters */
4133  while (my_isspace(charset_info,*param))
4134  param++;
4135  end= strmake(file_name, param, sizeof(file_name) - 1);
4136  /* remove end space from command line */
4137  while (end > file_name && (my_isspace(charset_info,end[-1]) ||
4138  my_iscntrl(charset_info,end[-1])))
4139  end--;
4140  end[0]= 0;
4141  if (end == file_name)
4142  {
4143  printf("No outfile specified!\n");
4144  return 0;
4145  }
4146  init_tee(file_name);
4147  return 0;
4148 }
4149 
4150 
4151 static int
4152 com_notee(String *buffer __attribute__((unused)),
4153  char *line __attribute__((unused)))
4154 {
4155  if (opt_outfile)
4156  end_tee();
4157  tee_fprintf(stdout, "Outfile disabled.\n");
4158  return 0;
4159 }
4160 
4161 /*
4162  Sorry, this command is not available in Windows.
4163 */
4164 
4165 #ifdef USE_POPEN
4166 static int
4167 com_pager(String *buffer __attribute__((unused)),
4168  char *line __attribute__((unused)))
4169 {
4170  char pager_name[FN_REFLEN], *end, *param;
4171 
4172  if (status.batch)
4173  return 0;
4174  /* Skip spaces in front of the pager command */
4175  while (my_isspace(charset_info, *line))
4176  line++;
4177  /* Skip the pager command */
4178  param= strchr(line, ' ');
4179  /* Skip the spaces between the command and the argument */
4180  while (param && my_isspace(charset_info, *param))
4181  param++;
4182  if (!param || !strlen(param)) // if pager was not given, use the default
4183  {
4184  if (!default_pager_set)
4185  {
4186  tee_fprintf(stdout, "Default pager wasn't set, using stdout.\n");
4187  opt_nopager=1;
4188  strmov(pager, "stdout");
4189  PAGER= stdout;
4190  return 0;
4191  }
4192  strmov(pager, default_pager);
4193  }
4194  else
4195  {
4196  end= strmake(pager_name, param, sizeof(pager_name)-1);
4197  while (end > pager_name && (my_isspace(charset_info,end[-1]) ||
4198  my_iscntrl(charset_info,end[-1])))
4199  end--;
4200  end[0]=0;
4201  strmov(pager, pager_name);
4202  strmov(default_pager, pager_name);
4203  }
4204  opt_nopager=0;
4205  tee_fprintf(stdout, "PAGER set to '%s'\n", pager);
4206  return 0;
4207 }
4208 
4209 
4210 static int
4211 com_nopager(String *buffer __attribute__((unused)),
4212  char *line __attribute__((unused)))
4213 {
4214  strmov(pager, "stdout");
4215  opt_nopager=1;
4216  PAGER= stdout;
4217  tee_fprintf(stdout, "PAGER set to stdout\n");
4218  return 0;
4219 }
4220 #endif
4221 
4222 
4223 /*
4224  Sorry, you can't send the result to an editor in Win32
4225 */
4226 
4227 #ifdef USE_POPEN
4228 static int
4229 com_edit(String *buffer,char *line __attribute__((unused)))
4230 {
4231  char filename[FN_REFLEN],buff[160];
4232  int fd,tmp;
4233  const char *editor;
4234 
4235  if ((fd=create_temp_file(filename,NullS,"sql", O_CREAT | O_WRONLY,
4236  MYF(MY_WME))) < 0)
4237  goto err;
4238  if (buffer->is_empty() && !old_buffer.is_empty())
4239  (void) my_write(fd,(uchar*) old_buffer.ptr(),old_buffer.length(),
4240  MYF(MY_WME));
4241  else
4242  (void) my_write(fd,(uchar*) buffer->ptr(),buffer->length(),MYF(MY_WME));
4243  (void) my_close(fd,MYF(0));
4244 
4245  if (!(editor = (char *)getenv("EDITOR")) &&
4246  !(editor = (char *)getenv("VISUAL")))
4247  editor = "vi";
4248  strxmov(buff,editor," ",filename,NullS);
4249  if(system(buff) == -1)
4250  goto err;
4251 
4252  MY_STAT stat_arg;
4253  if (!my_stat(filename,&stat_arg,MYF(MY_WME)))
4254  goto err;
4255  if ((fd = my_open(filename,O_RDONLY, MYF(MY_WME))) < 0)
4256  goto err;
4257  (void) buffer->alloc((uint) stat_arg.st_size);
4258  if ((tmp=read(fd,(char*) buffer->ptr(),buffer->alloced_length())) >= 0L)
4259  buffer->length((uint) tmp);
4260  else
4261  buffer->length(0);
4262  (void) my_close(fd,MYF(0));
4263  (void) my_delete(filename,MYF(MY_WME));
4264 err:
4265  return 0;
4266 }
4267 #endif
4268 
4269 
4270 /* If arg is given, exit without errors. This happens on command 'quit' */
4271 
4272 static int
4273 com_quit(String *buffer __attribute__((unused)),
4274  char *line __attribute__((unused)))
4275 {
4276  status.exit_status=0;
4277  return 1;
4278 }
4279 
4280 static int
4281 com_rehash(String *buffer __attribute__((unused)),
4282  char *line __attribute__((unused)))
4283 {
4284 #ifdef HAVE_READLINE
4285  build_completion_hash(1, 0);
4286 #endif
4287  return 0;
4288 }
4289 
4290 
4291 #ifdef USE_POPEN
4292 static int
4293 com_shell(String *buffer __attribute__((unused)),
4294  char *line __attribute__((unused)))
4295 {
4296  char *shell_cmd;
4297 
4298  /* Skip space from line begin */
4299  while (my_isspace(charset_info, *line))
4300  line++;
4301  if (!(shell_cmd = strchr(line, ' ')))
4302  {
4303  put_info("Usage: \\! shell-command", INFO_ERROR);
4304  return -1;
4305  }
4306  /*
4307  The output of the shell command does not
4308  get directed to the pager or the outfile
4309  */
4310  if (system(shell_cmd) == -1)
4311  {
4312  put_info(strerror(errno), INFO_ERROR, errno);
4313  return -1;
4314  }
4315  return 0;
4316 }
4317 #endif
4318 
4319 
4320 static int
4321 com_print(String *buffer,char *line __attribute__((unused)))
4322 {
4323  tee_puts("--------------", stdout);
4324  (void) tee_fputs(buffer->c_ptr(), stdout);
4325  if (!buffer->length() || (*buffer)[buffer->length()-1] != '\n')
4326  tee_putc('\n', stdout);
4327  tee_puts("--------------\n", stdout);
4328  return 0; /* If empty buffer */
4329 }
4330 
4331  /* ARGSUSED */
4332 static int
4333 com_connect(String *buffer, char *line)
4334 {
4335  char *tmp, buff[256];
4336  bool save_rehash= opt_rehash;
4337  int error;
4338 
4339  memset(buff, 0, sizeof(buff));
4340  if (buffer)
4341  {
4342  /*
4343  Two null bytes are needed in the end of buff to allow
4344  get_arg to find end of string the second time it's called.
4345  */
4346  tmp= strmake(buff, line, sizeof(buff)-2);
4347 #ifdef EXTRA_DEBUG
4348  tmp[1]= 0;
4349 #endif
4350  tmp= get_arg(buff, 0);
4351  if (tmp && *tmp)
4352  {
4353  my_free(current_db);
4354  current_db= my_strdup(tmp, MYF(MY_WME));
4355  tmp= get_arg(buff, 1);
4356  if (tmp)
4357  {
4358  my_free(current_host);
4359  current_host=my_strdup(tmp,MYF(MY_WME));
4360  }
4361  }
4362  else
4363  {
4364  /* Quick re-connect */
4365  opt_rehash= 0; /* purecov: tested */
4366  }
4367  buffer->length(0); // command used
4368  }
4369  else
4370  opt_rehash= 0;
4371  error=sql_connect(current_host,current_db,current_user,opt_password,0);
4372  opt_rehash= save_rehash;
4373 
4374  if (connected)
4375  {
4376  sprintf(buff,"Connection id: %lu",mysql_thread_id(&mysql));
4377  put_info(buff,INFO_INFO);
4378  sprintf(buff,"Current database: %.128s\n",
4379  current_db ? current_db : "*** NONE ***");
4380  put_info(buff,INFO_INFO);
4381  }
4382  return error;
4383 }
4384 
4385 
4386 static int com_source(String *buffer __attribute__((unused)),
4387  char *line)
4388 {
4389  char source_name[FN_REFLEN], *end, *param;
4390  LINE_BUFFER *line_buff;
4391  int error;
4392  STATUS old_status;
4393  FILE *sql_file;
4394 
4395  /* Skip space from file name */
4396  while (my_isspace(charset_info,*line))
4397  line++;
4398  if (!(param = strchr(line, ' '))) // Skip command name
4399  return put_info("Usage: \\. <filename> | source <filename>",
4400  INFO_ERROR, 0);
4401  while (my_isspace(charset_info,*param))
4402  param++;
4403  end=strmake(source_name,param,sizeof(source_name)-1);
4404  while (end > source_name && (my_isspace(charset_info,end[-1]) ||
4405  my_iscntrl(charset_info,end[-1])))
4406  end--;
4407  end[0]=0;
4408  unpack_filename(source_name,source_name);
4409  /* open file name */
4410  if (!(sql_file = my_fopen(source_name, O_RDONLY | O_BINARY,MYF(0))))
4411  {
4412  char buff[FN_REFLEN+60];
4413  sprintf(buff,"Failed to open file '%s', error: %d", source_name,errno);
4414  return put_info(buff, INFO_ERROR, 0);
4415  }
4416 
4417  if (!(line_buff= batch_readline_init(MAX_BATCH_BUFFER_SIZE, sql_file)))
4418  {
4419  my_fclose(sql_file,MYF(0));
4420  return put_info("Can't initialize batch_readline", INFO_ERROR, 0);
4421  }
4422 
4423  /* Save old status */
4424  old_status=status;
4425  memset(&status, 0, sizeof(status));
4426 
4427  status.batch=old_status.batch; // Run in batch mode
4428  status.line_buff=line_buff;
4429  status.file_name=source_name;
4430  glob_buffer.length(0); // Empty command buffer
4431  error= read_and_execute(false);
4432  status=old_status; // Continue as before
4433  my_fclose(sql_file,MYF(0));
4434  batch_readline_end(line_buff);
4435  return error;
4436 }
4437 
4438 
4439  /* ARGSUSED */
4440 static int
4441 com_delimiter(String *buffer __attribute__((unused)), char *line)
4442 {
4443  char buff[256], *tmp;
4444 
4445  strmake(buff, line, sizeof(buff) - 1);
4446  tmp= get_arg(buff, 0);
4447 
4448  if (!tmp || !*tmp)
4449  {
4450  put_info("DELIMITER must be followed by a 'delimiter' character or string",
4451  INFO_ERROR);
4452  return 0;
4453  }
4454  else
4455  {
4456  if (strstr(tmp, "\\"))
4457  {
4458  put_info("DELIMITER cannot contain a backslash character", INFO_ERROR);
4459  return 0;
4460  }
4461  }
4462  strmake(delimiter, tmp, sizeof(delimiter) - 1);
4463  delimiter_length= (int)strlen(delimiter);
4464  delimiter_str= delimiter;
4465  return 0;
4466 }
4467 
4468  /* ARGSUSED */
4469 static int
4470 com_use(String *buffer __attribute__((unused)), char *line)
4471 {
4472  char *tmp, buff[FN_REFLEN + 1];
4473  int select_db;
4474 
4475  memset(buff, 0, sizeof(buff));
4476 
4477  /*
4478  In case number of quotes exceed 2, we try to get
4479  the normalized db name.
4480  */
4481  if (get_quote_count(line) > 2)
4482  {
4483  if (normalize_dbname(line, buff, sizeof(buff)))
4484  return put_error(&mysql);
4485  tmp= buff;
4486  }
4487  else
4488  {
4489  strmake(buff, line, sizeof(buff) - 1);
4490  tmp= get_arg(buff, 0);
4491  }
4492 
4493  if (!tmp || !*tmp)
4494  {
4495  put_info("USE must be followed by a database name", INFO_ERROR);
4496  return 0;
4497  }
4498  /*
4499  We need to recheck the current database, because it may change
4500  under our feet, for example if DROP DATABASE or RENAME DATABASE
4501  (latter one not yet available by the time the comment was written)
4502  */
4503  get_current_db();
4504 
4505  if (!current_db || cmp_database(charset_info, current_db,tmp))
4506  {
4507  if (one_database)
4508  {
4509  skip_updates= 1;
4510  select_db= 0; // don't do mysql_select_db()
4511  }
4512  else
4513  select_db= 2; // do mysql_select_db() and build_completion_hash()
4514  }
4515  else
4516  {
4517  /*
4518  USE to the current db specified.
4519  We do need to send mysql_select_db() to make server
4520  update database level privileges, which might
4521  change since last USE (see bug#10979).
4522  For performance purposes, we'll skip rebuilding of completion hash.
4523  */
4524  skip_updates= 0;
4525  select_db= 1; // do only mysql_select_db(), without completion
4526  }
4527 
4528  if (select_db)
4529  {
4530  /*
4531  reconnect once if connection is down or if connection was found to
4532  be down during query
4533  */
4534  if (!connected && reconnect())
4535  return opt_reconnect ? -1 : 1; // Fatal error
4536  if (mysql_select_db(&mysql,tmp))
4537  {
4538  if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR)
4539  return put_error(&mysql);
4540 
4541  if (reconnect())
4542  return opt_reconnect ? -1 : 1; // Fatal error
4543  if (mysql_select_db(&mysql,tmp))
4544  return put_error(&mysql);
4545  }
4546  my_free(current_db);
4547  current_db=my_strdup(tmp,MYF(MY_WME));
4548 #ifdef HAVE_READLINE
4549  if (select_db > 1)
4550  build_completion_hash(opt_rehash, 1);
4551 #endif
4552  }
4553 
4554  put_info("Database changed",INFO_INFO);
4555  return 0;
4556 }
4557 
4577 static int
4578 normalize_dbname(const char *line, char *buff, uint buff_size)
4579 {
4580  MYSQL_RES *res= NULL;
4581 
4582  /* Send the "USE db" commmand to the server. */
4583  if (mysql_query(&mysql, line))
4584  return 1;
4585 
4586  /*
4587  Now, get the normalized database name and store it
4588  into the buff.
4589  */
4590  if (!mysql_query(&mysql, "SELECT DATABASE()") &&
4591  (res= mysql_use_result(&mysql)))
4592  {
4593  MYSQL_ROW row= mysql_fetch_row(res);
4594  if (row && row[0])
4595  {
4596  size_t len= strlen(row[0]);
4597  /* Make sure there is enough room to store the dbname. */
4598  if ((len > buff_size) || ! memcpy(buff, row[0], len))
4599  {
4600  mysql_free_result(res);
4601  return 1;
4602  }
4603  }
4604  mysql_free_result(res);
4605  }
4606 
4607  /* Restore the original database. */
4608  if (current_db && mysql_select_db(&mysql, current_db))
4609  return 1;
4610 
4611  return 0;
4612 }
4613 
4614 static int
4615 com_warnings(String *buffer __attribute__((unused)),
4616  char *line __attribute__((unused)))
4617 {
4618  show_warnings = 1;
4619  put_info("Show warnings enabled.",INFO_INFO);
4620  return 0;
4621 }
4622 
4623 static int
4624 com_nowarnings(String *buffer __attribute__((unused)),
4625  char *line __attribute__((unused)))
4626 {
4627  show_warnings = 0;
4628  put_info("Show warnings disabled.",INFO_INFO);
4629  return 0;
4630 }
4631 
4632 /*
4633  Gets argument from a command on the command line. If get_next_arg is
4634  not defined, skips the command and returns the first argument. The
4635  line is modified by adding zero to the end of the argument. If
4636  get_next_arg is defined, then the function searches for end of string
4637  first, after found, returns the next argument and adds zero to the
4638  end. If you ever wish to use this feature, remember to initialize all
4639  items in the array to zero first.
4640 */
4641 
4642 char *get_arg(char *line, my_bool get_next_arg)
4643 {
4644  char *ptr, *start;
4645  my_bool quoted= 0, valid_arg= 0;
4646  char qtype= 0;
4647 
4648  ptr= line;
4649  if (get_next_arg)
4650  {
4651  for (; *ptr; ptr++) ;
4652  if (*(ptr + 1))
4653  ptr++;
4654  }
4655  else
4656  {
4657  /* skip leading white spaces */
4658  while (my_isspace(charset_info, *ptr))
4659  ptr++;
4660  if (*ptr == '\\') // short command was used
4661  ptr+= 2;
4662  else
4663  while (*ptr &&!my_isspace(charset_info, *ptr)) // skip command
4664  ptr++;
4665  }
4666  if (!*ptr)
4667  return NullS;
4668  while (my_isspace(charset_info, *ptr))
4669  ptr++;
4670  if (*ptr == '\'' || *ptr == '\"' || *ptr == '`')
4671  {
4672  qtype= *ptr;
4673  quoted= 1;
4674  ptr++;
4675  }
4676  for (start=ptr ; *ptr; ptr++)
4677  {
4678  if (*ptr == '\\' && ptr[1]) // escaped character
4679  {
4680  // Remove the backslash
4681  strmov_overlapp(ptr, ptr+1);
4682  }
4683  else if ((!quoted && *ptr == ' ') || (quoted && *ptr == qtype))
4684  {
4685  *ptr= 0;
4686  break;
4687  }
4688  }
4689  valid_arg= ptr != start;
4690  return valid_arg ? start : NullS;
4691 }
4692 
4693 /*
4694  Number of quotes present in the command's argument.
4695 */
4696 static int
4697 get_quote_count(const char *line)
4698 {
4699  int quote_count;
4700  const char *ptr= line;
4701 
4702  for(quote_count= 0; ptr ++ && *ptr; ptr= strpbrk(ptr, "\"\'`"))
4703  quote_count ++;
4704 
4705  return quote_count;
4706 }
4707 
4708 static int
4709 sql_real_connect(char *host,char *database,char *user,char *password,
4710  uint silent)
4711 {
4712  my_bool handle_expired= (opt_connect_expired_password || !status.batch) ?
4713  TRUE : FALSE;
4714 
4715  if (connected)
4716  {
4717  connected= 0;
4718  mysql_close(&mysql);
4719  }
4720  mysql_init(&mysql);
4721  if (opt_init_command)
4722  mysql_options(&mysql, MYSQL_INIT_COMMAND, opt_init_command);
4723  if (opt_connect_timeout)
4724  {
4725  uint timeout=opt_connect_timeout;
4726  mysql_options(&mysql,MYSQL_OPT_CONNECT_TIMEOUT,
4727  (char*) &timeout);
4728  }
4729  if (opt_bind_addr)
4730  mysql_options(&mysql, MYSQL_OPT_BIND, opt_bind_addr);
4731  if (opt_compress)
4732  mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
4733  if (!opt_secure_auth)
4734  mysql_options(&mysql, MYSQL_SECURE_AUTH, (char *) &opt_secure_auth);
4735  if (using_opt_local_infile)
4736  mysql_options(&mysql,MYSQL_OPT_LOCAL_INFILE, (char*) &opt_local_infile);
4737 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4738  if (opt_use_ssl)
4739  {
4740  mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
4741  opt_ssl_capath, opt_ssl_cipher);
4742  mysql_options(&mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl);
4743  mysql_options(&mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath);
4744  }
4745  mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
4746  (char*)&opt_ssl_verify_server_cert);
4747 #endif
4748  if (opt_protocol)
4749  mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
4750 #ifdef HAVE_SMEM
4751  if (shared_memory_base_name)
4752  mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
4753 #endif
4754  if (safe_updates)
4755  {
4756  char init_command[100];
4757  sprintf(init_command,
4758  "SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=%lu,MAX_JOIN_SIZE=%lu",
4759  select_limit,max_join_size);
4760  mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command);
4761  }
4762 
4763  mysql_set_character_set(&mysql, default_charset);
4764 #ifdef __WIN__
4765  uint cnv_errors;
4766  String converted_database, converted_user;
4767  if (!my_charset_same(&my_charset_utf8mb4_bin, mysql.charset))
4768  {
4769  /* Convert user and database from UTF8MB4 to connection character set */
4770  if (user)
4771  {
4772  converted_user.copy(user, strlen(user) + 1,
4773  &my_charset_utf8mb4_bin, mysql.charset,
4774  &cnv_errors);
4775  user= (char *) converted_user.ptr();
4776  }
4777  if (database)
4778  {
4779  converted_database.copy(database, strlen(database) + 1,
4780  &my_charset_utf8mb4_bin, mysql.charset,
4781  &cnv_errors);
4782  database= (char *) converted_database.ptr();
4783  }
4784  }
4785 #endif
4786 
4787  if (opt_plugin_dir && *opt_plugin_dir)
4788  mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
4789 
4790  if (opt_default_auth && *opt_default_auth)
4791  mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
4792 
4793 #if !defined(HAVE_YASSL)
4794  if (opt_server_public_key && *opt_server_public_key)
4795  mysql_options(&mysql, MYSQL_SERVER_PUBLIC_KEY, opt_server_public_key);
4796 #endif
4797 
4798  if (using_opt_enable_cleartext_plugin)
4799  mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
4800  (char*) &opt_enable_cleartext_plugin);
4801 
4802  mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
4803  mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
4804  "program_name", "mysql");
4805  mysql_options(&mysql, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, &handle_expired);
4806 
4807  if (!mysql_real_connect(&mysql, host, user, password,
4808  database, opt_mysql_port, opt_mysql_unix_port,
4809  connect_flag | CLIENT_MULTI_STATEMENTS))
4810  {
4811  if (!silent ||
4812  (mysql_errno(&mysql) != CR_CONN_HOST_ERROR &&
4813  mysql_errno(&mysql) != CR_CONNECTION_ERROR))
4814  {
4815  (void) put_error(&mysql);
4816  (void) fflush(stdout);
4817  return ignore_errors ? -1 : 1; // Abort
4818  }
4819  return -1; // Retryable
4820  }
4821 
4822 #ifdef __WIN__
4823  /* Convert --execute buffer from UTF8MB4 to connection character set */
4824  if (!execute_buffer_conversion_done++ &&
4825  status.line_buff &&
4826  !status.line_buff->file && /* Convert only -e buffer, not real file */
4827  status.line_buff->buffer < status.line_buff->end && /* Non-empty */
4828  !my_charset_same(&my_charset_utf8mb4_bin, mysql.charset))
4829  {
4830  String tmp;
4831  size_t len= status.line_buff->end - status.line_buff->buffer;
4832  uint dummy_errors;
4833  /*
4834  Don't convert trailing '\n' character - it was appended during
4835  last batch_readline_command() call.
4836  Oherwise we'll get an extra line, which makes some tests fail.
4837  */
4838  if (status.line_buff->buffer[len - 1] == '\n')
4839  len--;
4840  if (tmp.copy(status.line_buff->buffer, len,
4841  &my_charset_utf8mb4_bin, mysql.charset, &dummy_errors))
4842  return 1;
4843 
4844  /* Free the old line buffer */
4845  batch_readline_end(status.line_buff);
4846 
4847  /* Re-initialize line buffer from the converted string */
4848  if (!(status.line_buff= batch_readline_command(NULL, (char *) tmp.c_ptr_safe())))
4849  return 1;
4850  }
4851 #endif /* __WIN__ */
4852 
4853  charset_info= mysql.charset;
4854 
4855  connected=1;
4856 #ifndef EMBEDDED_LIBRARY
4857  mysql.reconnect= debug_info_flag; // We want to know if this happens
4858 #else
4859  mysql.reconnect= 1;
4860 #endif
4861 #ifdef HAVE_READLINE
4862  build_completion_hash(opt_rehash, 1);
4863 #endif
4864  return 0;
4865 }
4866 
4867 
4868 static int
4869 sql_connect(char *host,char *database,char *user,char *password,uint silent)
4870 {
4871  bool message=0;
4872  uint count=0;
4873  int error;
4874  for (;;)
4875  {
4876  if ((error=sql_real_connect(host,database,user,password,wait_flag)) >= 0)
4877  {
4878  if (count)
4879  {
4880  tee_fputs("\n", stderr);
4881  (void) fflush(stderr);
4882  }
4883  return error;
4884  }
4885  if (!wait_flag)
4886  return ignore_errors ? -1 : 1;
4887  if (!message && !silent)
4888  {
4889  message=1;
4890  tee_fputs("Waiting",stderr); (void) fflush(stderr);
4891  }
4892  (void) sleep(wait_time);
4893  if (!silent)
4894  {
4895  putc('.',stderr); (void) fflush(stderr);
4896  count++;
4897  }
4898  }
4899 }
4900 
4901 
4902 
4903 static int
4904 com_status(String *buffer __attribute__((unused)),
4905  char *line __attribute__((unused)))
4906 {
4907  const char *status_str;
4908  char buff[40];
4909  ulonglong id;
4910  MYSQL_RES *result;
4911  LINT_INIT(result);
4912 
4913  if (mysql_real_query_for_lazy(
4914  C_STRING_WITH_LEN("select DATABASE(), USER() limit 1")))
4915  return 0;
4916 
4917  tee_puts("--------------", stdout);
4918  usage(1); /* Print version */
4919  tee_fprintf(stdout, "\nConnection id:\t\t%lu\n",mysql_thread_id(&mysql));
4920  /*
4921  Don't remove "limit 1",
4922  it is protection againts SQL_SELECT_LIMIT=0
4923  */
4924  if (!mysql_store_result_for_lazy(&result))
4925  {
4926  MYSQL_ROW cur=mysql_fetch_row(result);
4927  if (cur)
4928  {
4929  tee_fprintf(stdout, "Current database:\t%s\n", cur[0] ? cur[0] : "");
4930  tee_fprintf(stdout, "Current user:\t\t%s\n", cur[1]);
4931  }
4932  mysql_free_result(result);
4933  }
4934 
4935 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4936  if ((status_str= mysql_get_ssl_cipher(&mysql)))
4937  tee_fprintf(stdout, "SSL:\t\t\tCipher in use is %s\n",
4938  status_str);
4939  else
4940 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
4941  tee_puts("SSL:\t\t\tNot in use", stdout);
4942 
4943  if (skip_updates)
4944  {
4945  vidattr(A_BOLD);
4946  tee_fprintf(stdout, "\nAll updates ignored to this database\n");
4947  vidattr(A_NORMAL);
4948  }
4949 #ifdef USE_POPEN
4950  tee_fprintf(stdout, "Current pager:\t\t%s\n", pager);
4951  tee_fprintf(stdout, "Using outfile:\t\t'%s'\n", opt_outfile ? outfile : "");
4952 #endif
4953  tee_fprintf(stdout, "Using delimiter:\t%s\n", delimiter);
4954  tee_fprintf(stdout, "Server version:\t\t%s\n", server_version_string(&mysql));
4955  tee_fprintf(stdout, "Protocol version:\t%d\n", mysql_get_proto_info(&mysql));
4956  tee_fprintf(stdout, "Connection:\t\t%s\n", mysql_get_host_info(&mysql));
4957  if ((id= mysql_insert_id(&mysql)))
4958  tee_fprintf(stdout, "Insert id:\t\t%s\n", llstr(id, buff));
4959 
4960  /* "limit 1" is protection against SQL_SELECT_LIMIT=0 */
4961  if (mysql_real_query_for_lazy(C_STRING_WITH_LEN(
4962  "select @@character_set_client, @@character_set_connection, "
4963  "@@character_set_server, @@character_set_database limit 1")))
4964  {
4965  if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR)
4966  return 0;
4967  }
4968  if (!mysql_store_result_for_lazy(&result))
4969  {
4970  MYSQL_ROW cur=mysql_fetch_row(result);
4971  if (cur)
4972  {
4973  tee_fprintf(stdout, "Server characterset:\t%s\n", cur[2] ? cur[2] : "");
4974  tee_fprintf(stdout, "Db characterset:\t%s\n", cur[3] ? cur[3] : "");
4975  tee_fprintf(stdout, "Client characterset:\t%s\n", cur[0] ? cur[0] : "");
4976  tee_fprintf(stdout, "Conn. characterset:\t%s\n", cur[1] ? cur[1] : "");
4977  }
4978  mysql_free_result(result);
4979  }
4980  else
4981  {
4982  /* Probably pre-4.1 server */
4983  tee_fprintf(stdout, "Client characterset:\t%s\n", charset_info->csname);
4984  tee_fprintf(stdout, "Server characterset:\t%s\n", mysql.charset->csname);
4985  }
4986 
4987 #ifndef EMBEDDED_LIBRARY
4988  if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || ! mysql.unix_socket)
4989  tee_fprintf(stdout, "TCP port:\t\t%d\n", mysql.port);
4990  else
4991  tee_fprintf(stdout, "UNIX socket:\t\t%s\n", mysql.unix_socket);
4992  if (mysql.net.compress)
4993  tee_fprintf(stdout, "Protocol:\t\tCompressed\n");
4994 #endif
4995 
4996  if ((status_str= mysql_stat(&mysql)) && !mysql_error(&mysql)[0])
4997  {
4998  ulong sec;
4999  const char *pos= strchr(status_str,' ');
5000  /* print label */
5001  tee_fprintf(stdout, "%.*s\t\t\t", (int) (pos-status_str), status_str);
5002  if ((status_str= str2int(pos,10,0,LONG_MAX,(long*) &sec)))
5003  {
5004  nice_time((double) sec,buff,0);
5005  tee_puts(buff, stdout); /* print nice time */
5006  while (*status_str == ' ')
5007  status_str++; /* to next info */
5008  tee_putc('\n', stdout);
5009  tee_puts(status_str, stdout);
5010  }
5011  }
5012  if (safe_updates)
5013  {
5014  vidattr(A_BOLD);
5015  tee_fprintf(stdout, "\nNote that you are running in safe_update_mode:\n");
5016  vidattr(A_NORMAL);
5017  tee_fprintf(stdout, "\
5018 UPDATEs and DELETEs that don't use a key in the WHERE clause are not allowed.\n\
5019 (One can force an UPDATE/DELETE by adding LIMIT # at the end of the command.)\n\
5020 SELECT has an automatic 'LIMIT %lu' if LIMIT is not used.\n\
5021 Max number of examined row combination in a join is set to: %lu\n\n",
5022 select_limit, max_join_size);
5023  }
5024  tee_puts("--------------\n", stdout);
5025  return 0;
5026 }
5027 
5028 static const char *
5029 server_version_string(MYSQL *con)
5030 {
5031  /* Only one thread calls this, so no synchronization is needed */
5032  if (server_version == NULL)
5033  {
5034  MYSQL_RES *result;
5035 
5036  /* "limit 1" is protection against SQL_SELECT_LIMIT=0 */
5037  if (!mysql_query(con, "select @@version_comment limit 1") &&
5038  (result = mysql_use_result(con)))
5039  {
5040  MYSQL_ROW cur = mysql_fetch_row(result);
5041  if (cur && cur[0])
5042  {
5043  /* version, space, comment, \0 */
5044  size_t len= strlen(mysql_get_server_info(con)) + strlen(cur[0]) + 2;
5045 
5046  if ((server_version= (char *) my_malloc(len, MYF(MY_WME))))
5047  {
5048  char *bufp;
5049  bufp = strmov(server_version, mysql_get_server_info(con));
5050  bufp = strmov(bufp, " ");
5051  (void) strmov(bufp, cur[0]);
5052  }
5053  }
5054  mysql_free_result(result);
5055  }
5056 
5057  /*
5058  If for some reason we didn't get a version_comment, we'll
5059  keep things simple.
5060  */
5061 
5062  if (server_version == NULL)
5063  server_version= my_strdup(mysql_get_server_info(con), MYF(MY_WME));
5064  }
5065 
5066  return server_version ? server_version : "";
5067 }
5068 
5069 static int
5070 put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate)
5071 {
5072  FILE *file= (info_type == INFO_ERROR ? stderr : stdout);
5073  static int inited=0;
5074 
5075  if (status.batch)
5076  {
5077  if (info_type == INFO_ERROR)
5078  {
5079  (void) fflush(file);
5080  fprintf(file,"ERROR");
5081  if (error)
5082  {
5083  if (sqlstate)
5084  (void) fprintf(file," %d (%s)",error, sqlstate);
5085  else
5086  (void) fprintf(file," %d",error);
5087  }
5088  if (status.query_start_line && line_numbers)
5089  {
5090  (void) fprintf(file," at line %lu",status.query_start_line);
5091  if (status.file_name)
5092  (void) fprintf(file," in file: '%s'", status.file_name);
5093  }
5094  (void) fprintf(file,": %s\n",str);
5095  (void) fflush(file);
5096  if (!ignore_errors)
5097  return 1;
5098  }
5099  else if (info_type == INFO_RESULT && verbose > 1)
5100  tee_puts(str, file);
5101  if (unbuffered)
5102  fflush(file);
5103  return info_type == INFO_ERROR ? -1 : 0;
5104  }
5105  if (!opt_silent || info_type == INFO_ERROR)
5106  {
5107  if (!inited)
5108  {
5109  inited=1;
5110 #ifdef HAVE_SETUPTERM
5111  (void) setupterm((char *)0, 1, (int *) 0);
5112 #endif
5113  }
5114  if (info_type == INFO_ERROR)
5115  {
5116  if (!opt_nobeep)
5117  putchar('\a'); /* This should make a bell */
5118  vidattr(A_STANDOUT);
5119  if (error)
5120  {
5121  if (sqlstate)
5122  (void) tee_fprintf(file, "ERROR %d (%s): ", error, sqlstate);
5123  else
5124  (void) tee_fprintf(file, "ERROR %d: ", error);
5125  }
5126  else
5127  tee_puts("ERROR: ", file);
5128  }
5129  else
5130  vidattr(A_BOLD);
5131  (void) tee_puts(str, file);
5132  vidattr(A_NORMAL);
5133  }
5134  if (unbuffered)
5135  fflush(file);
5136  return info_type == INFO_ERROR ? -1 : 0;
5137 }
5138 
5139 
5140 static int
5141 put_error(MYSQL *con)
5142 {
5143  return put_info(mysql_error(con), INFO_ERROR, mysql_errno(con),
5144  mysql_sqlstate(con));
5145 }
5146 
5147 
5148 static void remove_cntrl(String &buffer)
5149 {
5150  char *start,*end;
5151  end=(start=(char*) buffer.ptr())+buffer.length();
5152  while (start < end && !my_isgraph(charset_info,end[-1]))
5153  end--;
5154  buffer.length((uint) (end-start));
5155 }
5156 
5157 
5168 void tee_write(FILE *file, const char *s, size_t slen, int flags)
5169 {
5170 #ifdef __WIN__
5171  my_bool is_console= my_win_is_console_cached(file);
5172 #endif
5173  const char *se;
5174  for (se= s + slen; s < se; s++)
5175  {
5176  const char *t;
5177 
5178  if (flags & MY_PRINT_MB)
5179  {
5180  int mblen;
5181  if (use_mb(charset_info) &&
5182  (mblen= my_ismbchar(charset_info, s, se)))
5183  {
5184 #ifdef __WIN__
5185  if (is_console)
5186  my_win_console_write(charset_info, s, mblen);
5187  else
5188 #endif
5189  fwrite(s, 1, mblen, file);
5190  if (opt_outfile)
5191  fwrite(s, 1, mblen, OUTFILE);
5192  s+= mblen - 1;
5193  continue;
5194  }
5195  }
5196 
5197  if ((flags & MY_PRINT_XML) && (t= array_value(xmlmeta, *s)))
5198  tee_fputs(t, file);
5199  else if ((flags & MY_PRINT_SPS_0) && *s == '\0')
5200  tee_putc((int) ' ', file); // This makes everything hard
5201  else if ((flags & MY_PRINT_ESC_0) && *s == '\0')
5202  tee_fputs("\\0", file); // This makes everything hard
5203  else if ((flags & MY_PRINT_CTRL) && *s == '\t')
5204  tee_fputs("\\t", file); // This would destroy tab format
5205  else if ((flags & MY_PRINT_CTRL) && *s == '\n')
5206  tee_fputs("\\n", file); // This too
5207  else if ((flags & MY_PRINT_CTRL) && *s == '\\')
5208  tee_fputs("\\\\", file);
5209  else
5210  {
5211 #ifdef __WIN__
5212  if (is_console)
5213  my_win_console_putc(charset_info, (int) *s);
5214  else
5215 #endif
5216  putc((int) *s, file);
5217  if (opt_outfile)
5218  putc((int) *s, OUTFILE);
5219  }
5220  }
5221 }
5222 
5223 
5224 void tee_fprintf(FILE *file, const char *fmt, ...)
5225 {
5226  va_list args;
5227 
5228  va_start(args, fmt);
5229 #ifdef __WIN__
5230  if (my_win_is_console_cached(file))
5231  my_win_console_vfprintf(charset_info, fmt, args);
5232  else
5233 #endif
5234  (void) vfprintf(file, fmt, args);
5235  va_end(args);
5236 
5237  if (opt_outfile)
5238  {
5239  va_start(args, fmt);
5240  (void) vfprintf(OUTFILE, fmt, args);
5241  va_end(args);
5242  }
5243 }
5244 
5245 
5246 /*
5247  Write a 0-terminated string to file and OUTFILE.
5248  TODO: possibly it's nice to have a version with length some day,
5249  e.g. tee_fnputs(s, slen, file),
5250  to print numerous ASCII constant strings among mysql.cc
5251  code, to avoid strlen(s) in my_win_console_fputs().
5252 */
5253 void tee_fputs(const char *s, FILE *file)
5254 {
5255 #ifdef __WIN__
5256  if (my_win_is_console_cached(file))
5257  my_win_console_fputs(charset_info, s);
5258  else
5259 #endif
5260  fputs(s, file);
5261  if (opt_outfile)
5262  fputs(s, OUTFILE);
5263 }
5264 
5265 
5266 void tee_puts(const char *s, FILE *file)
5267 {
5268  tee_fputs(s, file);
5269  tee_putc('\n', file);
5270 }
5271 
5272 void tee_putc(int c, FILE *file)
5273 {
5274 #ifdef __WIN__
5275  if (my_win_is_console_cached(file))
5276  my_win_console_putc(charset_info, c);
5277  else
5278 #endif
5279  putc(c, file);
5280  if (opt_outfile)
5281  putc(c, OUTFILE);
5282 }
5283 
5284 #if defined(__WIN__)
5285 #include <time.h>
5286 #else
5287 #include <sys/times.h>
5288 #ifdef _SC_CLK_TCK // For mit-pthreads
5289 #undef CLOCKS_PER_SEC
5290 #define CLOCKS_PER_SEC (sysconf(_SC_CLK_TCK))
5291 #endif
5292 #endif
5293 
5294 static ulong start_timer(void)
5295 {
5296 #if defined(__WIN__)
5297  return clock();
5298 #else
5299  struct tms tms_tmp;
5300  return times(&tms_tmp);
5301 #endif
5302 }
5303 
5304 
5310 static void nice_time(double sec,char *buff,bool part_second)
5311 {
5312  ulong tmp;
5313  if (sec >= 3600.0*24)
5314  {
5315  tmp=(ulong) floor(sec/(3600.0*24));
5316  sec-=3600.0*24*tmp;
5317  buff=int10_to_str((long) tmp, buff, 10);
5318  buff=strmov(buff,tmp > 1 ? " days " : " day ");
5319  }
5320  if (sec >= 3600.0)
5321  {
5322  tmp=(ulong) floor(sec/3600.0);
5323  sec-=3600.0*tmp;
5324  buff=int10_to_str((long) tmp, buff, 10);
5325  buff=strmov(buff,tmp > 1 ? " hours " : " hour ");
5326  }
5327  if (sec >= 60.0)
5328  {
5329  tmp=(ulong) floor(sec/60.0);
5330  sec-=60.0*tmp;
5331  buff=int10_to_str((long) tmp, buff, 10);
5332  buff=strmov(buff," min ");
5333  }
5334  if (part_second)
5335  sprintf(buff,"%.2f sec",sec);
5336  else
5337  sprintf(buff,"%d sec",(int) sec);
5338 }
5339 
5340 
5341 static void end_timer(ulong start_time,char *buff)
5342 {
5343  nice_time((double) (start_timer() - start_time) /
5344  CLOCKS_PER_SEC,buff,1);
5345 }
5346 
5347 
5348 static void mysql_end_timer(ulong start_time,char *buff)
5349 {
5350  buff[0]=' ';
5351  buff[1]='(';
5352  end_timer(start_time,buff+2);
5353  strmov(strend(buff),")");
5354 }
5355 
5356 static const char* construct_prompt()
5357 {
5358  processed_prompt.free(); // Erase the old prompt
5359  time_t lclock = time(NULL); // Get the date struct
5360  struct tm *t = localtime(&lclock);
5361 
5362  /* parse thru the settings for the prompt */
5363  for (char *c = current_prompt; *c ; c++)
5364  {
5365  if (*c != PROMPT_CHAR)
5366  processed_prompt.append(*c);
5367  else
5368  {
5369  switch (*++c) {
5370  case '\0':
5371  c--; // stop it from going beyond if ends with %
5372  break;
5373  case 'c':
5374  add_int_to_prompt(++prompt_counter);
5375  break;
5376  case 'v':
5377  if (connected)
5378  processed_prompt.append(mysql_get_server_info(&mysql));
5379  else
5380  processed_prompt.append("not_connected");
5381  break;
5382  case 'd':
5383  processed_prompt.append(current_db ? current_db : "(none)");
5384  break;
5385  case 'h':
5386  {
5387  const char *prompt;
5388  prompt= connected ? mysql_get_host_info(&mysql) : "not_connected";
5389  if (strstr(prompt, "Localhost"))
5390  processed_prompt.append("localhost");
5391  else
5392  {
5393  const char *end=strcend(prompt,' ');
5394  processed_prompt.append(prompt, (uint) (end-prompt));
5395  }
5396  break;
5397  }
5398  case 'p':
5399  {
5400 #ifndef EMBEDDED_LIBRARY
5401  if (!connected)
5402  {
5403  processed_prompt.append("not_connected");
5404  break;
5405  }
5406 
5407  const char *host_info = mysql_get_host_info(&mysql);
5408  if (strstr(host_info, "memory"))
5409  {
5410  processed_prompt.append( mysql.host );
5411  }
5412  else if (strstr(host_info,"TCP/IP") ||
5413  !mysql.unix_socket)
5414  add_int_to_prompt(mysql.port);
5415  else
5416  {
5417  char *pos=strrchr(mysql.unix_socket,'/');
5418  processed_prompt.append(pos ? pos+1 : mysql.unix_socket);
5419  }
5420 #endif
5421  }
5422  break;
5423  case 'U':
5424  if (!full_username)
5425  init_username();
5426  processed_prompt.append(full_username ? full_username :
5427  (current_user ? current_user : "(unknown)"));
5428  break;
5429  case 'u':
5430  if (!full_username)
5431  init_username();
5432  processed_prompt.append(part_username ? part_username :
5433  (current_user ? current_user : "(unknown)"));
5434  break;
5435  case PROMPT_CHAR:
5436  processed_prompt.append(PROMPT_CHAR);
5437  break;
5438  case 'n':
5439  processed_prompt.append('\n');
5440  break;
5441  case ' ':
5442  case '_':
5443  processed_prompt.append(' ');
5444  break;
5445  case 'R':
5446  if (t->tm_hour < 10)
5447  processed_prompt.append('0');
5448  add_int_to_prompt(t->tm_hour);
5449  break;
5450  case 'r':
5451  int getHour;
5452  getHour = t->tm_hour % 12;
5453  if (getHour == 0)
5454  getHour=12;
5455  if (getHour < 10)
5456  processed_prompt.append('0');
5457  add_int_to_prompt(getHour);
5458  break;
5459  case 'm':
5460  if (t->tm_min < 10)
5461  processed_prompt.append('0');
5462  add_int_to_prompt(t->tm_min);
5463  break;
5464  case 'y':
5465  int getYear;
5466  getYear = t->tm_year % 100;
5467  if (getYear < 10)
5468  processed_prompt.append('0');
5469  add_int_to_prompt(getYear);
5470  break;
5471  case 'Y':
5472  add_int_to_prompt(t->tm_year+1900);
5473  break;
5474  case 'D':
5475  char* dateTime;
5476  dateTime = ctime(&lclock);
5477  processed_prompt.append(strtok(dateTime,"\n"));
5478  break;
5479  case 's':
5480  if (t->tm_sec < 10)
5481  processed_prompt.append('0');
5482  add_int_to_prompt(t->tm_sec);
5483  break;
5484  case 'w':
5485  processed_prompt.append(day_names[t->tm_wday]);
5486  break;
5487  case 'P':
5488  processed_prompt.append(t->tm_hour < 12 ? "am" : "pm");
5489  break;
5490  case 'o':
5491  add_int_to_prompt(t->tm_mon+1);
5492  break;
5493  case 'O':
5494  processed_prompt.append(month_names[t->tm_mon]);
5495  break;
5496  case '\'':
5497  processed_prompt.append("'");
5498  break;
5499  case '"':
5500  processed_prompt.append('"');
5501  break;
5502  case 'S':
5503  processed_prompt.append(';');
5504  break;
5505  case 't':
5506  processed_prompt.append('\t');
5507  break;
5508  case 'l':
5509  processed_prompt.append(delimiter_str);
5510  break;
5511  default:
5512  processed_prompt.append(c);
5513  }
5514  }
5515  }
5516  processed_prompt.append('\0');
5517  return processed_prompt.ptr();
5518 }
5519 
5520 
5521 static void add_int_to_prompt(int toadd)
5522 {
5523  char buffer[16];
5524  int10_to_str(toadd,buffer,10);
5525  processed_prompt.append(buffer);
5526 }
5527 
5528 static void init_username()
5529 {
5530  my_free(full_username);
5531  my_free(part_username);
5532 
5533  MYSQL_RES *result;
5534  LINT_INIT(result);
5535  if (!mysql_query(&mysql,"select USER()") &&
5536  (result=mysql_use_result(&mysql)))
5537  {
5538  MYSQL_ROW cur=mysql_fetch_row(result);
5539  full_username=my_strdup(cur[0],MYF(MY_WME));
5540  part_username=my_strdup(strtok(cur[0],"@"),MYF(MY_WME));
5541  (void) mysql_fetch_row(result); // Read eof
5542  }
5543 }
5544 
5545 static int com_prompt(String *buffer __attribute__((unused)),
5546  char *line)
5547 {
5548  char *ptr=strchr(line, ' ');
5549  prompt_counter = 0;
5550  my_free(current_prompt);
5551  current_prompt=my_strdup(ptr ? ptr+1 : default_prompt,MYF(MY_WME));
5552  if (!ptr)
5553  tee_fprintf(stdout, "Returning to default PROMPT of %s\n", default_prompt);
5554  else
5555  tee_fprintf(stdout, "PROMPT set to '%s'\n", current_prompt);
5556  return 0;
5557 }