~drizzle-trunk/drizzle/development

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