~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;
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
144
static int verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0;
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1301
   (char**) &opt_rehash, (char**) &opt_rehash, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0,
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1308
    (char**) &auto_vertical_output, (char**) &auto_vertical_output, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
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,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1312
   "Directory where character sets are.", (char**) &charsets_dir,
1313
   (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
1314
  {"column-type-info", OPT_COLUMN_TYPES, "Display column type information.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1315
   (char**) &column_types_flag, (char**) &column_types_flag,
1 by brian
clean slate
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",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1319
   (char**) &preserve_comments, (char**) &preserve_comments,
1 by brian
clean slate
1320
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1321
  {"compress", 'C', "Use compression in server/client protocol.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1322
   (char**) &opt_compress, (char**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
1 by brian
clean slate
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
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1329
  {"debug", '#', "Output debug log", (char**) &default_dbug_option,
1330
   (char**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
1331
#endif
1332
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1333
   (char**) &debug_check_flag, (char**) &debug_check_flag, 0,
1 by brian
clean slate
1334
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1335
  {"debug-info", 'T', "Print some debug info at exit.", (char**) &debug_info_flag,
1336
   (char**) &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1337
  {"database", 'D', "Database to use.", (char**) &current_db,
1338
   (char**) &current_db, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
1339
  {"default-character-set", OPT_DEFAULT_CHARSET,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1340
   "Set the default character set.", (char**) &default_charset,
1341
   (char**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1342
  {"delimiter", OPT_DELIMITER, "Delimiter to be used.", (char**) &delimiter_str,
1343
   (char**) &delimiter_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1347
   (char**) &vertical, (char**) &vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
1 by brian
clean slate
1348
   0},
1349
  {"force", 'f', "Continue even if we get an sql error.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1350
   (char**) &ignore_errors, (char**) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1354
   (char**) &named_cmds, (char**) &named_cmds, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1362
   (char**) &opt_local_infile,
1363
   (char**) &opt_local_infile, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
1364
  {"no-beep", 'b', "Turn off beep on error.", (char**) &opt_nobeep,
1365
   (char**) &opt_nobeep, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 
1366
  {"host", 'h', "Connect to host.", (char**) &current_host,
1367
   (char**) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1368
  {"html", 'H', "Produce HTML output.", (char**) &opt_html, (char**) &opt_html,
1 by brian
clean slate
1369
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1370
  {"xml", 'X', "Produce XML output", (char**) &opt_xml, (char**) &opt_xml, 0,
1 by brian
clean slate
1371
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1372
  {"line-numbers", OPT_LINE_NUMBERS, "Write line numbers for errors.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1373
   (char**) &line_numbers, (char**) &line_numbers, 0, GET_BOOL,
1 by brian
clean slate
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},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1377
  {"unbuffered", 'n', "Flush buffer after each query.", (char**) &unbuffered,
1378
   (char**) &unbuffered, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
1379
  {"column-names", OPT_COLUMN_NAMES, "Write column names in results.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1380
   (char**) &column_names, (char**) &column_names, 0, GET_BOOL,
1 by brian
clean slate
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)",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1389
   (char**) &opt_sigint_ignore,  (char**) &opt_sigint_ignore, 0, GET_BOOL,
1 by brian
clean slate
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) ").",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1411
   (char**) &opt_mysql_port,
1412
   (char**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,  0},
1 by brian
clean slate
1413
  {"prompt", OPT_PROMPT, "Set the mysql prompt to this value.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1414
   (char**) &current_prompt, (char**) &current_prompt, 0, GET_STR_ALLOC,
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1420
   (char**) &quick, (char**) &quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
1421
  {"raw", 'r', "Write fields without conversion. Used with --batch.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1422
   (char**) &opt_raw_data, (char**) &opt_raw_data, 0, GET_BOOL, NO_ARG, 0, 0, 0,
1 by brian
clean slate
1423
   0, 0, 0},
1424
  {"reconnect", OPT_RECONNECT, "Reconnect if the connection is lost. Disable with --disable-reconnect. This option is enabled by default.", 
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1425
   (char**) &opt_reconnect, (char**) &opt_reconnect, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
1 by brian
clean slate
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,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1430
   "Base name of shared memory.", (char**) &shared_memory_base_name, (char**) &shared_memory_base_name, 
1 by brian
clean slate
1431
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1432
#endif
1433
  {"socket", 'S', "Socket file to use for connection.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1434
   (char**) &opt_mysql_unix_port, (char**) &opt_mysql_unix_port, 0, GET_STR_ALLOC,
1 by brian
clean slate
1435
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1436
  {"table", 't', "Output in table format.", (char**) &output_tables,
1437
   (char**) &output_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
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
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1444
  {"user", 'u', "User for login if not current user.", (char**) &current_user,
1445
   (char**) &current_user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
1446
#endif
1447
  {"safe-updates", 'U', "Only allow UPDATE and DELETE that uses keys.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1448
   (char**) &safe_updates, (char**) &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0,
1 by brian
clean slate
1449
   0, 0, 0, 0},
1450
  {"i-am-a-dummy", 'U', "Synonym for option --safe-updates, -U.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1451
   (char**) &safe_updates, (char**) &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0,
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1461
   (char**) &opt_connect_timeout,
1462
   (char**) &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3600*12, 0,
1 by brian
clean slate
1463
   0, 0},
1464
  {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET,
1465
   "Max packet length to send to, or receive from server",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1466
   (char**) &opt_max_allowed_packet, (char**) &opt_max_allowed_packet, 0,
1 by brian
clean slate
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",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1471
   (char**) &opt_net_buffer_length, (char**) &opt_net_buffer_length, 0, GET_ULONG,
1 by brian
clean slate
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",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1475
   (char**) &select_limit,
1476
   (char**) &select_limit, 0, GET_ULONG, REQUIRED_ARG, 1000L, 1, ULONG_MAX,
1 by brian
clean slate
1477
   0, 1, 0},
1478
  {"max_join_size", OPT_MAX_JOIN_SIZE,
1479
   "Automatic limit for rows in a join when using --safe-updates",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1480
   (char**) &max_join_size,
1481
   (char**) &max_join_size, 0, GET_ULONG, REQUIRED_ARG, 1000000L, 1, ULONG_MAX,
1 by brian
clean slate
1482
   0, 1, 0},
1483
  {"secure-auth", OPT_SECURE_AUTH, "Refuse client connecting to server if it"
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1484
    " uses old (pre-4.1.1) protocol", (char**) &opt_secure_auth,
1485
    (char**) &opt_secure_auth, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1489
    (char**) &show_warnings, (char**) &show_warnings, 0, GET_BOOL, NO_ARG, 
1 by brian
clean slate
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 &&
133 by Brian Aker
Cleanup of warning/errors.
1896
	((name && !my_strnncoll(charset_info,(uchar*)name,len, (uchar*)commands[i].name,len) && !commands[i].name[len] && (!end || (end && commands[i].takes_params))) || (!name && commands[i].cmd_char == cmd_char)))
1 by brian
clean slate
1897
    {
1898
      DBUG_PRINT("exit",("found command: %s", commands[i].name));
1899
      DBUG_RETURN(&commands[i]);
1900
    }
1901
  }
1902
  DBUG_RETURN((COMMANDS *) 0);
1903
}
1904
1905
1906
static bool add_line(String &buffer,char *line,char *in_string,
1907
                     bool *ml_comment)
1908
{
1909
  uchar inchar;
1910
  char buff[80], *pos, *out;
1911
  COMMANDS *com;
1912
  bool need_space= 0;
1913
  bool ss_comment= 0;
1914
  DBUG_ENTER("add_line");
1915
1916
  if (!line[0] && buffer.is_empty())
1917
    DBUG_RETURN(0);
1918
#ifdef HAVE_READLINE
1919
  if (status.add_to_history && line[0] && not_in_history(line))
1920
    add_history(line);
1921
#endif
1922
  char *end_of_line=line+(uint) strlen(line);
1923
1924
  for (pos=out=line ; (inchar= (uchar) *pos) ; pos++)
1925
  {
1926
    if (!preserve_comments)
1927
    {
1928
      // Skip spaces at the beggining of a statement
1929
      if (my_isspace(charset_info,inchar) && (out == line) &&
1930
          buffer.is_empty())
1931
        continue;
1932
    }
1933
        
1934
#ifdef USE_MB
1935
    // Accept multi-byte characters as-is
1936
    int length;
1937
    if (use_mb(charset_info) &&
1938
        (length= my_ismbchar(charset_info, pos, end_of_line)))
1939
    {
1940
      if (!*ml_comment || preserve_comments)
1941
      {
1942
        while (length--)
1943
          *out++ = *pos++;
1944
        pos--;
1945
      }
1946
      else
1947
        pos+= length - 1;
1948
      continue;
1949
    }
1950
#endif
1951
    if (!*ml_comment && inchar == '\\' &&
1952
        !(mysql.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES))
1953
    {
1954
      // Found possbile one character command like \c
1955
1956
      if (!(inchar = (uchar) *++pos))
1957
	break;				// readline adds one '\'
1958
      if (*in_string || inchar == 'N')	// \N is short for NULL
1959
      {					// Don't allow commands in string
1960
	*out++='\\';
1961
	*out++= (char) inchar;
1962
	continue;
1963
      }
1964
      if ((com=find_command(NullS,(char) inchar)))
1965
      {
1966
        // Flush previously accepted characters
1967
        if (out != line)
1968
        {
1969
          buffer.append(line, (uint) (out-line));
1970
          out= line;
1971
        }
1972
        
1973
        if ((*com->func)(&buffer,pos-1) > 0)
1974
          DBUG_RETURN(1);                       // Quit
1975
        if (com->takes_params)
1976
        {
1977
          if (ss_comment)
1978
          {
1979
            /*
1980
              If a client-side macro appears inside a server-side comment,
1981
              discard all characters in the comment after the macro (that is,
1982
              until the end of the comment rather than the next delimiter)
1983
            */
1984
            for (pos++; *pos && (*pos != '*' || *(pos + 1) != '/'); pos++)
1985
              ;
1986
            pos--;
1987
          }
1988
          else
1989
          {
1990
            for (pos++ ;
1991
                 *pos && (*pos != *delimiter ||
1992
                          !is_prefix(pos + 1, delimiter + 1)) ; pos++)
1993
              ;	// Remove parameters
1994
            if (!*pos)
1995
              pos--;
1996
            else 
1997
              pos+= delimiter_length - 1; // Point at last delim char
1998
          }
1999
        }
2000
      }
2001
      else
2002
      {
2003
	sprintf(buff,"Unknown command '\\%c'.",inchar);
2004
	if (put_info(buff,INFO_ERROR) > 0)
2005
	  DBUG_RETURN(1);
2006
	*out++='\\';
2007
	*out++=(char) inchar;
2008
	continue;
2009
      }
2010
    }
2011
    else if (!*ml_comment && !*in_string &&
2012
             (end_of_line - pos) >= 10 &&
2013
             !my_strnncoll(charset_info, (uchar*) pos, 10,
2014
                           (const uchar*) "delimiter ", 10))
2015
    {
2016
      // Flush previously accepted characters
2017
      if (out != line)
2018
      {
2019
        buffer.append(line, (uint32) (out - line));
2020
        out= line;
2021
      }
2022
2023
      // Flush possible comments in the buffer
2024
      if (!buffer.is_empty())
2025
      {
2026
        if (com_go(&buffer, 0) > 0) // < 0 is not fatal
2027
          DBUG_RETURN(1);
2028
        buffer.length(0);
2029
      }
2030
2031
      /*
2032
        Delimiter wants the get rest of the given line as argument to
2033
        allow one to change ';' to ';;' and back
2034
      */
2035
      buffer.append(pos);
2036
      if (com_delimiter(&buffer, pos) > 0)
2037
        DBUG_RETURN(1);
2038
2039
      buffer.length(0);
2040
      break;
2041
    }
2042
    else if (!*ml_comment && !*in_string && is_prefix(pos, delimiter))
2043
    {
2044
      // Found a statement. Continue parsing after the delimiter
2045
      pos+= delimiter_length;
2046
2047
      if (preserve_comments)
2048
      {
2049
        while (my_isspace(charset_info, *pos))
2050
          *out++= *pos++;
2051
      }
2052
      // Flush previously accepted characters
2053
      if (out != line)
2054
      {
2055
        buffer.append(line, (uint32) (out-line));
2056
        out= line;
2057
      }
2058
2059
      if (preserve_comments && ((*pos == '#') ||
2060
                                ((*pos == '-') &&
2061
                                 (pos[1] == '-') &&
2062
                                 my_isspace(charset_info, pos[2]))))
2063
      {
2064
        // Add trailing single line comments to this statement
2065
        buffer.append(pos);
2066
        pos+= strlen(pos);
2067
      }
2068
2069
      pos--;
2070
2071
      if ((com= find_command(buffer.c_ptr(), 0)))
2072
      {
2073
          
2074
        if ((*com->func)(&buffer, buffer.c_ptr()) > 0)
2075
          DBUG_RETURN(1);                       // Quit 
2076
      }
2077
      else
2078
      {
2079
        if (com_go(&buffer, 0) > 0)             // < 0 is not fatal
2080
          DBUG_RETURN(1);
2081
      }
2082
      buffer.length(0);
2083
    }
2084
    else if (!*ml_comment && (!*in_string && (inchar == '#' ||
133 by Brian Aker
Cleanup of warning/errors.
2085
			      (inchar == '-' && pos[1] == '-' && my_isspace(charset_info,pos[2])))))
1 by brian
clean slate
2086
    {
2087
      // Flush previously accepted characters
2088
      if (out != line)
2089
      {
2090
        buffer.append(line, (uint32) (out - line));
2091
        out= line;
2092
      }
2093
2094
      // comment to end of line
2095
      if (preserve_comments)
2096
        buffer.append(pos);
2097
2098
      break;
2099
    }
2100
    else if (!*in_string && inchar == '/' && *(pos+1) == '*' &&
2101
	     *(pos+2) != '!')
2102
    {
2103
      if (preserve_comments)
2104
      {
2105
        *out++= *pos++;                       // copy '/'
2106
        *out++= *pos;                         // copy '*'
2107
      }
2108
      else
2109
        pos++;
2110
      *ml_comment= 1;
2111
      if (out != line)
2112
      {
2113
        buffer.append(line,(uint) (out-line));
2114
        out=line;
2115
      }
2116
    }
2117
    else if (*ml_comment && !ss_comment && inchar == '*' && *(pos + 1) == '/')
2118
    {
2119
      if (preserve_comments)
2120
      {
2121
        *out++= *pos++;                       // copy '*'
2122
        *out++= *pos;                         // copy '/'
2123
      }
2124
      else
2125
        pos++;
2126
      *ml_comment= 0;
2127
      if (out != line)
2128
      {
2129
        buffer.append(line, (uint32) (out - line));
2130
        out= line;
2131
      }
2132
      // Consumed a 2 chars or more, and will add 1 at most,
2133
      // so using the 'line' buffer to edit data in place is ok.
2134
      need_space= 1;
2135
    }      
2136
    else
2137
    {						// Add found char to buffer
2138
      if (!*in_string && inchar == '/' && *(pos + 1) == '*' &&
2139
          *(pos + 2) == '!')
2140
        ss_comment= 1;
2141
      else if (!*in_string && ss_comment && inchar == '*' && *(pos + 1) == '/')
2142
        ss_comment= 0;
2143
      if (inchar == *in_string)
2144
	*in_string= 0;
2145
      else if (!*ml_comment && !*in_string &&
2146
	       (inchar == '\'' || inchar == '"' || inchar == '`'))
2147
	*in_string= (char) inchar;
2148
      if (!*ml_comment || preserve_comments)
2149
      {
2150
        if (need_space && !my_isspace(charset_info, (char)inchar))
2151
          *out++= ' ';
2152
        need_space= 0;
2153
        *out++= (char) inchar;
2154
      }
2155
    }
2156
  }
2157
  if (out != line || !buffer.is_empty())
2158
  {
2159
    *out++='\n';
2160
    uint length=(uint) (out-line);
2161
    if (buffer.length() + length >= buffer.alloced_length())
2162
      buffer.realloc(buffer.length()+length+IO_SIZE);
2163
    if ((!*ml_comment || preserve_comments) && buffer.append(line, length))
2164
      DBUG_RETURN(1);
2165
  }
2166
  DBUG_RETURN(0);
2167
}
2168
2169
/*****************************************************************
2170
	    Interface to Readline Completion
2171
******************************************************************/
2172
2173
#ifdef HAVE_READLINE
2174
2175
static char *new_command_generator(const char *text, int);
2176
extern "C" char **new_mysql_completion (const char *text, int start, int end);
2177
2178
/*
2179
  Tell the GNU Readline library how to complete.  We want to try to complete
2180
  on command names if this is the first word in the line, or on filenames
2181
  if not.
2182
*/
2183
2184
#if defined(USE_NEW_READLINE_INTERFACE) || defined(USE_LIBEDIT_INTERFACE)
2185
extern "C" char *no_completion(const char*,int)
2186
#else
2187
extern "C" char *no_completion()
2188
#endif
2189
{
2190
  return 0;					/* No filename completion */
2191
}
2192
2193
/*	glues pieces of history back together if in pieces   */
2194
static void fix_history(String *final_command) 
2195
{
2196
  int total_lines = 1;
2197
  char *ptr = final_command->c_ptr();
2198
  String fixed_buffer; 	/* Converted buffer */
2199
  char str_char = '\0';  /* Character if we are in a string or not */
2200
  
2201
  /* find out how many lines we have and remove newlines */
2202
  while (*ptr != '\0') 
2203
  {
2204
    switch (*ptr) {
2205
      /* string character */
2206
    case '"':
2207
    case '\'':
2208
    case '`':
2209
      if (str_char == '\0')	/* open string */
2210
	str_char = *ptr;
2211
      else if (str_char == *ptr)   /* close string */
2212
	str_char = '\0';
2213
      fixed_buffer.append(ptr,1);
2214
      break;
2215
    case '\n':
2216
      /* 
2217
	 not in string, change to space
2218
	 if in string, leave it alone 
2219
      */
2220
      fixed_buffer.append(str_char == '\0' ? " " : "\n");
2221
      total_lines++;
2222
      break;
2223
    case '\\':
2224
      fixed_buffer.append('\\');
2225
      /* need to see if the backslash is escaping anything */
2226
      if (str_char) 
2227
      {
2228
	ptr++;
2229
	/* special characters that need escaping */
2230
	if (*ptr == '\'' || *ptr == '"' || *ptr == '\\')
2231
	  fixed_buffer.append(ptr,1);
2232
	else
2233
	  ptr--;
2234
      }
2235
      break;
2236
      
2237
    default:
2238
      fixed_buffer.append(ptr,1);
2239
    }
2240
    ptr++;
2241
  }
2242
  if (total_lines > 1)			
2243
    add_history(fixed_buffer.ptr());
2244
}
2245
2246
/*	
2247
  returns 0 if line matches the previous history entry
2248
  returns 1 if the line doesn't match the previous history entry
2249
*/
2250
static int not_in_history(const char *line) 
2251
{
2252
  HIST_ENTRY *oldhist = history_get(history_length);
2253
  
2254
  if (oldhist == 0)
2255
    return 1;
2256
  if (strcmp(oldhist->line,line) == 0)
2257
    return 0;
2258
  return 1;
2259
}
2260
2261
static void initialize_readline (char *name)
2262
{
2263
  /* Allow conditional parsing of the ~/.inputrc file. */
2264
  rl_readline_name = name;
2265
2266
  /* Tell the completer that we want a crack first. */
2267
  rl_attempted_completion_function= (rl_completion_func_t*)&new_mysql_completion;
2268
  rl_completion_entry_function= (rl_compentry_func_t*)&no_completion;
2269
}
2270
2271
/*
2272
  Attempt to complete on the contents of TEXT.  START and END show the
2273
  region of TEXT that contains the word to complete.  We can use the
2274
  entire line in case we want to do some simple parsing.  Return the
2275
  array of matches, or NULL if there aren't any.
2276
*/
2277
2278
char **new_mysql_completion (const char *text,
2279
                             int start __attribute__((unused)),
2280
                             int end __attribute__((unused)))
2281
{
2282
  if (!status.batch && !quick)
2283
    return rl_completion_matches(text, new_command_generator);
2284
  else
2285
    return (char**) 0;
2286
}
2287
2288
static char *new_command_generator(const char *text,int state)
2289
{
2290
  static int textlen;
2291
  char *ptr;
2292
  static Bucket *b;
2293
  static entry *e;
2294
  static uint i;
2295
2296
  if (!state)
2297
    textlen=(uint) strlen(text);
2298
2299
  if (textlen>0)
2300
  {						/* lookup in the hash */
2301
    if (!state)
2302
    {
2303
      uint len;
2304
2305
      b = find_all_matches(&ht,text,(uint) strlen(text),&len);
2306
      if (!b)
2307
	return NullS;
2308
      e = b->pData;
2309
    }
2310
2311
    if (e)
2312
    {
2313
      ptr= strdup(e->str);
2314
      e = e->pNext;
2315
      return ptr;
2316
    }
2317
  }
2318
  else
2319
  { /* traverse the entire hash, ugly but works */
2320
2321
    if (!state)
2322
    {
2323
      /* find the first used bucket */
2324
      for (i=0 ; i < ht.nTableSize ; i++)
2325
      {
2326
	if (ht.arBuckets[i])
2327
	{
2328
	  b = ht.arBuckets[i];
2329
	  e = b->pData;
2330
	  break;
2331
	}
2332
      }
2333
    }
2334
    ptr= NullS;
2335
    while (e && !ptr)
2336
    {					/* find valid entry in bucket */
2337
      if ((uint) strlen(e->str) == b->nKeyLength)
2338
	ptr = strdup(e->str);
2339
      /* find the next used entry */
2340
      e = e->pNext;
2341
      if (!e)
2342
      { /* find the next used bucket */
2343
	b = b->pNext;
2344
	if (!b)
2345
	{
2346
	  for (i++ ; i<ht.nTableSize; i++)
2347
	  {
2348
	    if (ht.arBuckets[i])
2349
	    {
2350
	      b = ht.arBuckets[i];
2351
	      e = b->pData;
2352
	      break;
2353
	    }
2354
	  }
2355
	}
2356
	else
2357
	  e = b->pData;
2358
      }
2359
    }
2360
    if (ptr)
2361
      return ptr;
2362
  }
2363
  return NullS;
2364
}
2365
2366
2367
/* Build up the completion hash */
2368
2369
static void build_completion_hash(bool rehash, bool write_info)
2370
{
2371
  COMMANDS *cmd=commands;
2372
  MYSQL_RES *databases=0,*tables=0;
2373
  MYSQL_RES *fields;
2374
  static char ***field_names= 0;
2375
  MYSQL_ROW database_row,table_row;
2376
  MYSQL_FIELD *sql_field;
2377
  char buf[NAME_LEN*2+2];		 // table name plus field name plus 2
2378
  int i,j,num_fields;
2379
  DBUG_ENTER("build_completion_hash");
2380
2381
  if (status.batch || quick || !current_db)
2382
    DBUG_VOID_RETURN;			// We don't need completion in batches
2383
  if (!rehash)
2384
    DBUG_VOID_RETURN;
2385
2386
  /* Free old used memory */
2387
  if (field_names)
2388
    field_names=0;
2389
  completion_hash_clean(&ht);
2390
  free_root(&hash_mem_root,MYF(0));
2391
2392
  /* hash this file's known subset of SQL commands */
2393
  while (cmd->name) {
2394
    add_word(&ht,(char*) cmd->name);
2395
    cmd++;
2396
  }
2397
77.1.40 by Monty Taylor
More naming changes.
2398
  /* hash Drizzle functions (to be implemented) */
1 by brian
clean slate
2399
2400
  /* hash all database names */
2401
  if (mysql_query(&mysql,"show databases") == 0)
2402
  {
2403
    if (!(databases = mysql_store_result(&mysql)))
2404
      put_info(mysql_error(&mysql),INFO_INFO);
2405
    else
2406
    {
2407
      while ((database_row=mysql_fetch_row(databases)))
2408
      {
2409
	char *str=strdup_root(&hash_mem_root, (char*) database_row[0]);
2410
	if (str)
2411
	  add_word(&ht,(char*) str);
2412
      }
2413
      mysql_free_result(databases);
2414
    }
2415
  }
2416
  /* hash all table names */
2417
  if (mysql_query(&mysql,"show tables")==0)
2418
  {
2419
    if (!(tables = mysql_store_result(&mysql)))
2420
      put_info(mysql_error(&mysql),INFO_INFO);
2421
    else
2422
    {
2423
      if (mysql_num_rows(tables) > 0 && !opt_silent && write_info)
2424
      {
2425
	tee_fprintf(stdout, "\
2426
Reading table information for completion of table and column names\n\
2427
You can turn off this feature to get a quicker startup with -A\n\n");
2428
      }
2429
      while ((table_row=mysql_fetch_row(tables)))
2430
      {
2431
	char *str=strdup_root(&hash_mem_root, (char*) table_row[0]);
2432
	if (str &&
2433
	    !completion_hash_exists(&ht,(char*) str, (uint) strlen(str)))
2434
	  add_word(&ht,str);
2435
      }
2436
    }
2437
  }
2438
2439
  /* hash all field names, both with the table prefix and without it */
2440
  if (!tables)					/* no tables */
2441
  {
2442
    DBUG_VOID_RETURN;
2443
  }
2444
  mysql_data_seek(tables,0);
2445
  if (!(field_names= (char ***) alloc_root(&hash_mem_root,sizeof(char **) *
2446
					   (uint) (mysql_num_rows(tables)+1))))
2447
  {
2448
    mysql_free_result(tables);
2449
    DBUG_VOID_RETURN;
2450
  }
2451
  i=0;
2452
  while ((table_row=mysql_fetch_row(tables)))
2453
  {
2454
    if ((fields=mysql_list_fields(&mysql,(const char*) table_row[0],NullS)))
2455
    {
2456
      num_fields=mysql_num_fields(fields);
2457
      if (!(field_names[i] = (char **) alloc_root(&hash_mem_root,
2458
						  sizeof(char *) *
2459
						  (num_fields*2+1))))
2460
      {
2461
        mysql_free_result(fields);
2462
        break;
2463
      }
2464
      field_names[i][num_fields*2]= '\0';
2465
      j=0;
2466
      while ((sql_field=mysql_fetch_field(fields)))
2467
      {
2468
	sprintf(buf,"%.64s.%.64s",table_row[0],sql_field->name);
2469
	field_names[i][j] = strdup_root(&hash_mem_root,buf);
2470
	add_word(&ht,field_names[i][j]);
2471
	field_names[i][num_fields+j] = strdup_root(&hash_mem_root,
2472
						   sql_field->name);
2473
	if (!completion_hash_exists(&ht,field_names[i][num_fields+j],
2474
				    (uint) strlen(field_names[i][num_fields+j])))
2475
	  add_word(&ht,field_names[i][num_fields+j]);
2476
	j++;
2477
      }
2478
      mysql_free_result(fields);
2479
    }
2480
    else
2481
      field_names[i]= 0;
2482
2483
    i++;
2484
  }
2485
  mysql_free_result(tables);
2486
  field_names[i]=0;				// End pointer
2487
  DBUG_VOID_RETURN;
2488
}
2489
2490
	/* for gnu readline */
2491
2492
#ifndef HAVE_INDEX
2493
extern "C" {
2494
extern char *index(const char *,int c),*rindex(const char *,int);
2495
2496
char *index(const char *s,int c)
2497
{
2498
  for (;;)
2499
  {
2500
     if (*s == (char) c) return (char*) s;
2501
     if (!*s++) return NullS;
2502
  }
2503
}
2504
2505
char *rindex(const char *s,int c)
2506
{
2507
  register char *t;
2508
2509
  t = NullS;
2510
  do if (*s == (char) c) t = (char*) s; while (*s++);
2511
  return (char*) t;
2512
}
2513
}
2514
#endif
2515
#endif /* HAVE_READLINE */
2516
2517
2518
static int reconnect(void)
2519
{
2520
  /* purecov: begin tested */
2521
  if (opt_reconnect)
2522
  {
2523
    put_info("No connection. Trying to reconnect...",INFO_INFO);
2524
    (void) com_connect((String *) 0, 0);
2525
    if (opt_rehash)
2526
      com_rehash(NULL, NULL);
2527
  }
2528
  if (!connected)
2529
    return put_info("Can't connect to the server\n",INFO_ERROR);
2530
  /* purecov: end */
2531
  return 0;
2532
}
2533
2534
static void get_current_db()
2535
{
2536
  MYSQL_RES *res;
2537
2538
  my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
2539
  current_db= NULL;
2540
  /* In case of error below current_db will be NULL */
2541
  if (!mysql_query(&mysql, "SELECT DATABASE()") &&
2542
      (res= mysql_use_result(&mysql)))
2543
  {
2544
    MYSQL_ROW row= mysql_fetch_row(res);
2545
    if (row[0])
2546
      current_db= my_strdup(row[0], MYF(MY_WME));
2547
    mysql_free_result(res);
2548
  }
2549
}
2550
2551
/***************************************************************************
2552
 The different commands
2553
***************************************************************************/
2554
2555
int mysql_real_query_for_lazy(const char *buf, int length)
2556
{
2557
  for (uint retry=0;; retry++)
2558
  {
2559
    int error;
2560
    if (!mysql_real_query(&mysql,buf,length))
2561
      return 0;
2562
    error= put_error(&mysql);
2563
    if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 ||
2564
        !opt_reconnect)
2565
      return error;
2566
    if (reconnect())
2567
      return error;
2568
  }
2569
}
2570
2571
int mysql_store_result_for_lazy(MYSQL_RES **result)
2572
{
2573
  if ((*result=mysql_store_result(&mysql)))
2574
    return 0;
2575
2576
  if (mysql_error(&mysql)[0])
2577
    return put_error(&mysql);
2578
  return 0;
2579
}
2580
2581
static void print_help_item(MYSQL_ROW *cur, int num_name, int num_cat, char *last_char)
2582
{
2583
  char ccat= (*cur)[num_cat][0];
2584
  if (*last_char != ccat)
2585
  {
2586
    put_info(ccat == 'Y' ? "categories:" : "topics:", INFO_INFO);
2587
    *last_char= ccat;
2588
  }
2589
  tee_fprintf(PAGER, "   %s\n", (*cur)[num_name]);
2590
}
2591
2592
2593
static int com_server_help(String *buffer __attribute__((unused)),
2594
			   char *line __attribute__((unused)), char *help_arg)
2595
{
2596
  MYSQL_ROW cur;
2597
  const char *server_cmd= buffer->ptr();
2598
  char cmd_buf[100];
2599
  MYSQL_RES *result;
2600
  int error;
2601
  
2602
  if (help_arg[0] != '\'')
2603
  {
2604
	char *end_arg= strend(help_arg);
2605
	if(--end_arg)
2606
	{
2607
		while (my_isspace(charset_info,*end_arg))
2608
          end_arg--;
2609
		*++end_arg= '\0';
2610
	}
2611
	(void) strxnmov(cmd_buf, sizeof(cmd_buf), "help '", help_arg, "'", NullS);
2612
    server_cmd= cmd_buf;
2613
  }
2614
  
2615
  if (!status.batch)
2616
  {
2617
    old_buffer= *buffer;
2618
    old_buffer.copy();
2619
  }
2620
2621
  if (!connected && reconnect())
2622
    return 1;
2623
2624
  if ((error= mysql_real_query_for_lazy(server_cmd,(int)strlen(server_cmd))) ||
2625
      (error= mysql_store_result_for_lazy(&result)))
2626
    return error;
2627
2628
  if (result)
2629
  {
2630
    unsigned int num_fields= mysql_num_fields(result);
2631
    my_ulonglong num_rows= mysql_num_rows(result);
2632
    mysql_fetch_fields(result);
2633
    if (num_fields==3 && num_rows==1)
2634
    {
2635
      if (!(cur= mysql_fetch_row(result)))
2636
      {
2637
	error= -1;
2638
	goto err;
2639
      }
2640
2641
      init_pager();
2642
      tee_fprintf(PAGER,   "Name: \'%s\'\n", cur[0]);
2643
      tee_fprintf(PAGER,   "Description:\n%s", cur[1]);
2644
      if (cur[2] && *((char*)cur[2]))
2645
	tee_fprintf(PAGER, "Examples:\n%s", cur[2]);
2646
      tee_fprintf(PAGER,   "\n");
2647
      end_pager();
2648
    }
2649
    else if (num_fields >= 2 && num_rows)
2650
    {
2651
      init_pager();
2652
      char last_char= 0;
2653
2654
      int num_name= 0, num_cat= 0;
2655
2656
      if (num_fields == 2)
2657
      {
2658
	put_info("Many help items for your request exist.", INFO_INFO);
2659
	put_info("To make a more specific request, please type 'help <item>',\nwhere <item> is one of the following", INFO_INFO);
2660
	num_name= 0;
2661
	num_cat= 1;
2662
      }
2663
      else if ((cur= mysql_fetch_row(result)))
2664
      {
2665
	tee_fprintf(PAGER, "You asked for help about help category: \"%s\"\n", cur[0]);
2666
	put_info("For more information, type 'help <item>', where <item> is one of the following", INFO_INFO);
2667
	num_name= 1;
2668
	num_cat= 2;
2669
	print_help_item(&cur,1,2,&last_char);
2670
      }
2671
2672
      while ((cur= mysql_fetch_row(result)))
2673
	print_help_item(&cur,num_name,num_cat,&last_char);
2674
      tee_fprintf(PAGER, "\n");
2675
      end_pager();
2676
    }
2677
    else
2678
    {
2679
      put_info("\nNothing found", INFO_INFO);
2680
      put_info("Please try to run 'help contents' for a list of all accessible topics\n", INFO_INFO);
2681
    }
2682
  }
2683
2684
err:
2685
  mysql_free_result(result);
2686
  return error;
2687
}
2688
2689
static int
2690
com_help(String *buffer __attribute__((unused)),
2691
	 char *line __attribute__((unused)))
2692
{
2693
  register int i, j;
2694
  char * help_arg= strchr(line,' '), buff[32], *end;
2695
  if (help_arg)
2696
  {
2697
    while (my_isspace(charset_info,*help_arg))
2698
      help_arg++;
2699
	if (*help_arg)	  
2700
	  return com_server_help(buffer,line,help_arg);
2701
  }
2702
77.1.40 by Monty Taylor
More naming changes.
2703
  put_info("List of all Drizzle commands:", INFO_INFO);
1 by brian
clean slate
2704
  if (!named_cmds)
2705
    put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO);
2706
  for (i = 0; commands[i].name; i++)
2707
  {
2708
    end= strmov(buff, commands[i].name);
2709
    for (j= (int)strlen(commands[i].name); j < 10; j++)
2710
      end= strmov(end, " ");
2711
    if (commands[i].func)
2712
      tee_fprintf(stdout, "%s(\\%c) %s\n", buff,
2713
		  commands[i].cmd_char, commands[i].doc);
2714
  }
2715
  if (connected && mysql_get_server_version(&mysql) >= 40100)
2716
    put_info("\nFor server side help, type 'help contents'\n", INFO_INFO);
2717
  return 0;
2718
}
2719
2720
2721
	/* ARGSUSED */
2722
static int
2723
com_clear(String *buffer,char *line __attribute__((unused)))
2724
{
2725
#ifdef HAVE_READLINE
2726
  if (status.add_to_history)
2727
    fix_history(buffer);
2728
#endif
2729
  buffer->length(0);
2730
  return 0;
2731
}
2732
2733
	/* ARGSUSED */
2734
static int
2735
com_charset(String *buffer __attribute__((unused)), char *line)
2736
{
2737
  char buff[256], *param;
2738
  CHARSET_INFO * new_cs;
2739
  strmake(buff, line, sizeof(buff) - 1);
2740
  param= get_arg(buff, 0);
2741
  if (!param || !*param)
2742
  {
2743
    return put_info("Usage: \\C char_setname | charset charset_name", 
2744
		    INFO_ERROR, 0);
2745
  }
2746
  new_cs= get_charset_by_csname(param, MY_CS_PRIMARY, MYF(MY_WME));
2747
  if (new_cs)
2748
  {
2749
    charset_info= new_cs;
2750
    mysql_set_character_set(&mysql, charset_info->csname);
2751
    default_charset= (char *)charset_info->csname;
2752
    default_charset_used= 1;
2753
    put_info("Charset changed", INFO_INFO);
2754
  }
2755
  else put_info("Charset is not found", INFO_INFO);
2756
  return 0;
2757
}
2758
2759
/*
2760
  Execute command
2761
  Returns: 0  if ok
2762
          -1 if not fatal error
2763
	  1  if fatal error
2764
*/
2765
2766
2767
static int
2768
com_go(String *buffer,char *line __attribute__((unused)))
2769
{
2770
  char		buff[200]; /* about 110 chars used so far */
2771
  char		time_buff[52+3+1]; /* time max + space&parens + NUL */
2772
  MYSQL_RES	*result;
2773
  ulong		timer, warnings= 0;
2774
  uint		error= 0;
2775
  int           err= 0;
2776
2777
  interrupted_query= 0;
2778
  if (!status.batch)
2779
  {
2780
    old_buffer= *buffer;			// Save for edit command
2781
    old_buffer.copy();
2782
  }
2783
2784
  /* Remove garbage for nicer messages */
2785
  remove_cntrl(*buffer);
2786
2787
  if (buffer->is_empty())
2788
  {
2789
    if (status.batch)				// Ignore empty quries
2790
      return 0;
2791
    return put_info("No query specified\n",INFO_ERROR);
2792
2793
  }
2794
  if (!connected && reconnect())
2795
  {
2796
    buffer->length(0);				// Remove query on error
2797
    return opt_reconnect ? -1 : 1;          // Fatal error
2798
  }
2799
  if (verbose)
2800
    (void) com_print(buffer,0);
2801
2802
  if (skip_updates &&
2803
      (buffer->length() < 4 || my_strnncoll(charset_info,
2804
					    (const uchar*)buffer->ptr(),4,
2805
					    (const uchar*)"SET ",4)))
2806
  {
2807
    (void) put_info("Ignoring query to other database",INFO_INFO);
2808
    return 0;
2809
  }
2810
2811
  timer=start_timer();
2812
  executing_query= 1;
2813
  error= mysql_real_query_for_lazy(buffer->ptr(),buffer->length());
2814
2815
#ifdef HAVE_READLINE
2816
  if (status.add_to_history) 
2817
  {  
2818
    buffer->append(vertical ? "\\G" : delimiter);
2819
    /* Append final command onto history */
2820
    fix_history(buffer);
2821
  }
2822
#endif
2823
2824
  buffer->length(0);
2825
2826
  if (error)
2827
    goto end;
2828
2829
  do
2830
  {
2831
    char *pos;
2832
2833
    if (quick)
2834
    {
2835
      if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql))
2836
      {
2837
        error= put_error(&mysql);
2838
        goto end;
2839
      }
2840
    }
2841
    else
2842
    {
2843
      error= mysql_store_result_for_lazy(&result);
2844
      if (error)
2845
        goto end;
2846
    }
2847
2848
    if (verbose >= 3 || !opt_silent)
2849
      mysql_end_timer(timer,time_buff);
2850
    else
2851
      time_buff[0]= '\0';
2852
2853
    /* Every branch must truncate  buff . */
2854
    if (result)
2855
    {
2856
      if (!mysql_num_rows(result) && ! quick && !column_types_flag)
2857
      {
2858
	strmov(buff, "Empty set");
2859
        if (opt_xml)
2860
        { 
2861
          /*
2862
            We must print XML header and footer
2863
            to produce a well-formed XML even if
2864
            the result set is empty (Bug#27608).
2865
          */
2866
          init_pager();
2867
          print_table_data_xml(result);
2868
          end_pager();
2869
        }
2870
      }
2871
      else
2872
      {
2873
	init_pager();
2874
	if (opt_html)
2875
	  print_table_data_html(result);
2876
	else if (opt_xml)
2877
	  print_table_data_xml(result);
2878
  else if (vertical || (auto_vertical_output && (terminal_width < get_result_width(result))))
2879
	  print_table_data_vertically(result);
2880
	else if (opt_silent && verbose <= 2 && !output_tables)
2881
	  print_tab_data(result);
2882
	else
2883
	  print_table_data(result);
2884
	sprintf(buff,"%ld %s in set",
2885
		(long) mysql_num_rows(result),
2886
		(long) mysql_num_rows(result) == 1 ? "row" : "rows");
2887
	end_pager();
2888
        if (mysql_errno(&mysql))
2889
          error= put_error(&mysql);
2890
      }
2891
    }
2892
    else if (mysql_affected_rows(&mysql) == ~(ulonglong) 0)
2893
      strmov(buff,"Query OK");
2894
    else
2895
      sprintf(buff,"Query OK, %ld %s affected",
2896
	      (long) mysql_affected_rows(&mysql),
2897
	      (long) mysql_affected_rows(&mysql) == 1 ? "row" : "rows");
2898
2899
    pos=strend(buff);
2900
    if ((warnings= mysql_warning_count(&mysql)))
2901
    {
2902
      *pos++= ',';
2903
      *pos++= ' ';
2904
      pos=int10_to_str(warnings, pos, 10);
2905
      pos=strmov(pos, " warning");
2906
      if (warnings != 1)
2907
	*pos++= 's';
2908
    }
2909
    strmov(pos, time_buff);
2910
    put_info(buff,INFO_RESULT);
2911
    if (mysql_info(&mysql))
2912
      put_info(mysql_info(&mysql),INFO_RESULT);
2913
    put_info("",INFO_RESULT);			// Empty row
2914
2915
    if (result && !mysql_eof(result))	/* Something wrong when using quick */
2916
      error= put_error(&mysql);
2917
    else if (unbuffered)
2918
      fflush(stdout);
2919
    mysql_free_result(result);
2920
  } while (!(err= mysql_next_result(&mysql)));
2921
  if (err >= 1)
2922
    error= put_error(&mysql);
2923
2924
end:
2925
2926
 /* Show warnings if any or error occured */
2927
  if (show_warnings == 1 && (warnings >= 1 || error))
2928
    print_warnings();
2929
2930
  if (!error && !status.batch && 
2931
      (mysql.server_status & SERVER_STATUS_DB_DROPPED))
2932
    get_current_db();
2933
2934
  executing_query= 0;
2935
  return error;				/* New command follows */
2936
}
2937
2938
2939
static void init_pager()
2940
{
2941
#ifdef USE_POPEN
2942
  if (!opt_nopager)
2943
  {
2944
    if (!(PAGER= popen(pager, "w")))
2945
    {
2946
      tee_fprintf(stdout, "popen() failed! defaulting PAGER to stdout!\n");
2947
      PAGER= stdout;
2948
    }
2949
  }
2950
  else
2951
#endif
2952
    PAGER= stdout;
2953
}
2954
2955
static void end_pager()
2956
{
2957
#ifdef USE_POPEN
2958
  if (!opt_nopager)
2959
    pclose(PAGER);
2960
#endif
2961
}
2962
2963
2964
static void init_tee(const char *file_name)
2965
{
2966
  FILE* new_outfile;
2967
  if (opt_outfile)
2968
    end_tee();
2969
  if (!(new_outfile= my_fopen(file_name, O_APPEND | O_WRONLY, MYF(MY_WME))))
2970
  {
2971
    tee_fprintf(stdout, "Error logging to file '%s'\n", file_name);
2972
    return;
2973
  }
2974
  OUTFILE = new_outfile;
2975
  strmake(outfile, file_name, FN_REFLEN-1);
2976
  tee_fprintf(stdout, "Logging to file '%s'\n", file_name);
2977
  opt_outfile= 1;
2978
  return;
2979
}
2980
2981
2982
static void end_tee()
2983
{
2984
  my_fclose(OUTFILE, MYF(0));
2985
  OUTFILE= 0;
2986
  opt_outfile= 0;
2987
  return;
2988
}
2989
2990
2991
static int
2992
com_ego(String *buffer,char *line)
2993
{
2994
  int result;
2995
  bool oldvertical=vertical;
2996
  vertical=1;
2997
  result=com_go(buffer,line);
2998
  vertical=oldvertical;
2999
  return result;
3000
}
3001
3002
3003
static const char *fieldtype2str(enum enum_field_types type)
3004
{
3005
  switch (type) {
3006
    case MYSQL_TYPE_BLOB:        return "BLOB";
97 by Brian Aker
DATE cleanup.
3007
    case MYSQL_TYPE_NEWDATE:        return "DATE";
1 by brian
clean slate
3008
    case MYSQL_TYPE_DATETIME:    return "DATETIME";
80 by Brian Aker
Most of the removal of dead DECIMAL type
3009
    case MYSQL_TYPE_NEWDECIMAL:  return "DECIMAL";
1 by brian
clean slate
3010
    case MYSQL_TYPE_DOUBLE:      return "DOUBLE";
3011
    case MYSQL_TYPE_ENUM:        return "ENUM";
3012
    case MYSQL_TYPE_FLOAT:       return "FLOAT";
3013
    case MYSQL_TYPE_LONG:        return "LONG";
3014
    case MYSQL_TYPE_LONGLONG:    return "LONGLONG";
3015
    case MYSQL_TYPE_NULL:        return "NULL";
3016
    case MYSQL_TYPE_SET:         return "SET";
3017
    case MYSQL_TYPE_SHORT:       return "SHORT";
3018
    case MYSQL_TYPE_STRING:      return "STRING";
3019
    case MYSQL_TYPE_TIME:        return "TIME";
3020
    case MYSQL_TYPE_TIMESTAMP:   return "TIMESTAMP";
3021
    case MYSQL_TYPE_TINY:        return "TINY";
3022
    case MYSQL_TYPE_VAR_STRING:  return "VAR_STRING";
3023
    case MYSQL_TYPE_YEAR:        return "YEAR";
3024
    default:                     return "?-unknown-?";
3025
  }
3026
}
3027
3028
static char *fieldflags2str(uint f) {
3029
  static char buf[1024];
3030
  char *s=buf;
3031
  *s=0;
3032
#define ff2s_check_flag(X) \
3033
                if (f & X ## _FLAG) { s=strmov(s, # X " "); f &= ~ X ## _FLAG; }
3034
  ff2s_check_flag(NOT_NULL);
3035
  ff2s_check_flag(PRI_KEY);
3036
  ff2s_check_flag(UNIQUE_KEY);
3037
  ff2s_check_flag(MULTIPLE_KEY);
3038
  ff2s_check_flag(BLOB);
3039
  ff2s_check_flag(UNSIGNED);
3040
  ff2s_check_flag(ZEROFILL);
3041
  ff2s_check_flag(BINARY);
3042
  ff2s_check_flag(ENUM);
3043
  ff2s_check_flag(AUTO_INCREMENT);
3044
  ff2s_check_flag(TIMESTAMP);
3045
  ff2s_check_flag(SET);
3046
  ff2s_check_flag(NO_DEFAULT_VALUE);
3047
  ff2s_check_flag(NUM);
3048
  ff2s_check_flag(PART_KEY);
3049
  ff2s_check_flag(GROUP);
3050
  ff2s_check_flag(UNIQUE);
3051
  ff2s_check_flag(BINCMP);
3052
  ff2s_check_flag(ON_UPDATE_NOW);
3053
#undef ff2s_check_flag
3054
  if (f)
3055
    sprintf(s, " unknows=0x%04x", f);
3056
  return buf;
3057
}
3058
3059
static void
3060
print_field_types(MYSQL_RES *result)
3061
{
3062
  MYSQL_FIELD   *field;
3063
  uint i=0;
3064
3065
  while ((field = mysql_fetch_field(result)))
3066
  {
3067
    tee_fprintf(PAGER, "Field %3u:  `%s`\n"
3068
                       "Catalog:    `%s`\n"
3069
                       "Database:   `%s`\n"
3070
                       "Table:      `%s`\n"
3071
                       "Org_table:  `%s`\n"
3072
                       "Type:       %s\n"
3073
                       "Collation:  %s (%u)\n"
3074
                       "Length:     %lu\n"
3075
                       "Max_length: %lu\n"
3076
                       "Decimals:   %u\n"
3077
                       "Flags:      %s\n\n",
3078
                ++i,
3079
                field->name, field->catalog, field->db, field->table,
3080
                field->org_table, fieldtype2str(field->type),
3081
                get_charset_name(field->charsetnr), field->charsetnr,
3082
                field->length, field->max_length, field->decimals,
3083
                fieldflags2str(field->flags));
3084
  }
3085
  tee_puts("", PAGER);
3086
}
3087
3088
3089
static void
3090
print_table_data(MYSQL_RES *result)
3091
{
3092
  String separator(256);
3093
  MYSQL_ROW	cur;
3094
  MYSQL_FIELD	*field;
3095
  bool		*num_flag;
3096
3097
  num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result));
3098
  if (column_types_flag)
3099
  {
3100
    print_field_types(result);
3101
    if (!mysql_num_rows(result))
3102
      return;
3103
    mysql_field_seek(result,0);
3104
  }
3105
  separator.copy("+",1,charset_info);
3106
  while ((field = mysql_fetch_field(result)))
3107
  {
3108
    uint length= column_names ? field->name_length : 0;
3109
    if (quick)
3110
      length=max(length,field->length);
3111
    else
3112
      length=max(length,field->max_length);
3113
    if (length < 4 && !IS_NOT_NULL(field->flags))
3114
      length=4;					// Room for "NULL"
3115
    field->max_length=length;
3116
    separator.fill(separator.length()+length+2,'-');
3117
    separator.append('+');
3118
  }
3119
  separator.append('\0');                       // End marker for \0
3120
  tee_puts((char*) separator.ptr(), PAGER);
3121
  if (column_names)
3122
  {
3123
    mysql_field_seek(result,0);
3124
    (void) tee_fputs("|", PAGER);
3125
    for (uint off=0; (field = mysql_fetch_field(result)) ; off++)
3126
    {
3127
      uint name_length= (uint) strlen(field->name);
3128
      uint numcells= charset_info->cset->numcells(charset_info,
3129
                                                  field->name,
3130
                                                  field->name + name_length);
3131
      uint display_length= field->max_length + name_length - numcells;
3132
      tee_fprintf(PAGER, " %-*s |",(int) min(display_length,
3133
                                            MAX_COLUMN_LENGTH),
3134
                  field->name);
3135
      num_flag[off]= IS_NUM(field->type);
3136
    }
3137
    (void) tee_fputs("\n", PAGER);
3138
    tee_puts((char*) separator.ptr(), PAGER);
3139
  }
3140
3141
  while ((cur= mysql_fetch_row(result)))
3142
  {
3143
    if (interrupted_query)
3144
      break;
3145
    ulong *lengths= mysql_fetch_lengths(result);
3146
    (void) tee_fputs("| ", PAGER);
3147
    mysql_field_seek(result, 0);
3148
    for (uint off= 0; off < mysql_num_fields(result); off++)
3149
    {
3150
      const char *buffer;
3151
      uint data_length;
3152
      uint field_max_length;
3153
      uint visible_length;
3154
      uint extra_padding;
3155
3156
      if (cur[off] == NULL)
3157
      {
3158
        buffer= "NULL";
3159
        data_length= 4;
3160
      } 
3161
      else 
3162
      {
3163
        buffer= cur[off];
3164
        data_length= (uint) lengths[off];
3165
      }
3166
3167
      field= mysql_fetch_field(result);
3168
      field_max_length= field->max_length;
3169
3170
      /* 
3171
       How many text cells on the screen will this string span?  If it contains
3172
       multibyte characters, then the number of characters we occupy on screen
3173
       will be fewer than the number of bytes we occupy in memory.
3174
3175
       We need to find how much screen real-estate we will occupy to know how 
3176
       many extra padding-characters we should send with the printing function.
3177
      */
3178
      visible_length= charset_info->cset->numcells(charset_info, buffer, buffer + data_length);
3179
      extra_padding= data_length - visible_length;
3180
3181
      if (field_max_length > MAX_COLUMN_LENGTH)
3182
        tee_print_sized_data(buffer, data_length, MAX_COLUMN_LENGTH+extra_padding, FALSE);
3183
      else
3184
      {
3185
        if (num_flag[off] != 0) /* if it is numeric, we right-justify it */
3186
          tee_print_sized_data(buffer, data_length, field_max_length+extra_padding, TRUE);
3187
        else 
3188
          tee_print_sized_data(buffer, data_length, field_max_length+extra_padding, FALSE);
3189
      }
3190
      tee_fputs(" | ", PAGER);
3191
    }
3192
    (void) tee_fputs("\n", PAGER);
3193
  }
3194
  tee_puts((char*) separator.ptr(), PAGER);
3195
  my_afree((uchar*) num_flag);
3196
}
3197
3198
/**
3199
  Return the length of a field after it would be rendered into text.
3200
3201
  This doesn't know or care about multibyte characters.  Assume we're
3202
  using such a charset.  We can't know that all of the upcoming rows 
3203
  for this column will have bytes that each render into some fraction
3204
  of a character.  It's at least possible that a row has bytes that 
3205
  all render into one character each, and so the maximum length is 
3206
  still the number of bytes.  (Assumption 1:  This can't be better 
3207
  because we can never know the number of characters that the DB is 
3208
  going to send -- only the number of bytes.  2: Chars <= Bytes.)
3209
3210
  @param  field  Pointer to a field to be inspected
3211
3212
  @returns  number of character positions to be used, at most
3213
*/
3214
static int get_field_disp_length(MYSQL_FIELD *field)
3215
{
3216
  uint length= column_names ? field->name_length : 0;
3217
3218
  if (quick)
3219
    length= max(length, field->length);
3220
  else
3221
    length= max(length, field->max_length);
3222
3223
  if (length < 4 && !IS_NOT_NULL(field->flags))
3224
    length= 4;				/* Room for "NULL" */
3225
3226
  return length;
3227
}
3228
3229
/**
3230
  For a new result, return the max number of characters that any
3231
  upcoming row may return.
3232
3233
  @param  result  Pointer to the result to judge
3234
3235
  @returns  The max number of characters in any row of this result
3236
*/
3237
static int get_result_width(MYSQL_RES *result)
3238
{
3239
  unsigned int len= 0;
3240
  MYSQL_FIELD *field;
3241
  MYSQL_FIELD_OFFSET offset;
3242
  
3243
#ifndef DBUG_OFF
3244
  offset= mysql_field_tell(result);
3245
  DBUG_ASSERT(offset == 0);
3246
#else
3247
  offset= 0;
3248
#endif
3249
3250
  while ((field= mysql_fetch_field(result)) != NULL)
3251
    len+= get_field_disp_length(field) + 3; /* plus bar, space, & final space */
3252
3253
  (void) mysql_field_seek(result, offset);	
3254
3255
  return len + 1; /* plus final bar. */
3256
}
3257
3258
static void
3259
tee_print_sized_data(const char *data, unsigned int data_length, unsigned int total_bytes_to_send, bool right_justified)
3260
{
3261
  /* 
3262
    For '\0's print ASCII spaces instead, as '\0' is eaten by (at
3263
    least my) console driver, and that messes up the pretty table
3264
    grid.  (The \0 is also the reason we can't use fprintf() .) 
3265
  */
3266
  unsigned int i;
3267
  const char *p;
3268
3269
  if (right_justified) 
3270
    for (i= data_length; i < total_bytes_to_send; i++)
3271
      tee_putc((int)' ', PAGER);
3272
3273
  for (i= 0, p= data; i < data_length; i+= 1, p+= 1)
3274
  {
3275
    if (*p == '\0')
3276
      tee_putc((int)' ', PAGER);
3277
    else
3278
      tee_putc((int)*p, PAGER);
3279
  }
3280
3281
  if (! right_justified) 
3282
    for (i= data_length; i < total_bytes_to_send; i++)
3283
      tee_putc((int)' ', PAGER);
3284
}
3285
3286
3287
3288
static void
3289
print_table_data_html(MYSQL_RES *result)
3290
{
3291
  MYSQL_ROW	cur;
3292
  MYSQL_FIELD	*field;
3293
3294
  mysql_field_seek(result,0);
3295
  (void) tee_fputs("<TABLE BORDER=1><TR>", PAGER);
3296
  if (column_names)
3297
  {
3298
    while((field = mysql_fetch_field(result)))
3299
    {
3300
      tee_fprintf(PAGER, "<TH>%s</TH>", (field->name ? 
3301
					 (field->name[0] ? field->name : 
3302
					  " &nbsp; ") : "NULL"));
3303
    }
3304
    (void) tee_fputs("</TR>", PAGER);
3305
  }
3306
  while ((cur = mysql_fetch_row(result)))
3307
  {
3308
    if (interrupted_query)
3309
      break;
3310
    ulong *lengths=mysql_fetch_lengths(result);
3311
    (void) tee_fputs("<TR>", PAGER);
3312
    for (uint i=0; i < mysql_num_fields(result); i++)
3313
    {
3314
      (void) tee_fputs("<TD>", PAGER);
3315
      safe_put_field(cur[i],lengths[i]);
3316
      (void) tee_fputs("</TD>", PAGER);
3317
    }
3318
    (void) tee_fputs("</TR>", PAGER);
3319
  }
3320
  (void) tee_fputs("</TABLE>", PAGER);
3321
}
3322
3323
3324
static void
3325
print_table_data_xml(MYSQL_RES *result)
3326
{
3327
  MYSQL_ROW   cur;
3328
  MYSQL_FIELD *fields;
3329
3330
  mysql_field_seek(result,0);
3331
3332
  tee_fputs("<?xml version=\"1.0\"?>\n\n<resultset statement=\"", PAGER);
3333
  xmlencode_print(glob_buffer.ptr(), (int)strlen(glob_buffer.ptr()));
3334
  tee_fputs("\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">",
3335
            PAGER);
3336
3337
  fields = mysql_fetch_fields(result);
3338
  while ((cur = mysql_fetch_row(result)))
3339
  {
3340
    if (interrupted_query)
3341
      break;
3342
    ulong *lengths=mysql_fetch_lengths(result);
3343
    (void) tee_fputs("\n  <row>\n", PAGER);
3344
    for (uint i=0; i < mysql_num_fields(result); i++)
3345
    {
3346
      tee_fprintf(PAGER, "\t<field name=\"");
3347
      xmlencode_print(fields[i].name, (uint) strlen(fields[i].name));
3348
      if (cur[i])
3349
      {
3350
        tee_fprintf(PAGER, "\">");
3351
        xmlencode_print(cur[i], lengths[i]);
3352
        tee_fprintf(PAGER, "</field>\n");
3353
      }
3354
      else
3355
        tee_fprintf(PAGER, "\" xsi:nil=\"true\" />\n");
3356
    }
3357
    (void) tee_fputs("  </row>\n", PAGER);
3358
  }
3359
  (void) tee_fputs("</resultset>\n", PAGER);
3360
}
3361
3362
3363
static void
3364
print_table_data_vertically(MYSQL_RES *result)
3365
{
3366
  MYSQL_ROW	cur;
3367
  uint		max_length=0;
3368
  MYSQL_FIELD	*field;
3369
3370
  while ((field = mysql_fetch_field(result)))
3371
  {
3372
    uint length= field->name_length;
3373
    if (length > max_length)
3374
      max_length= length;
3375
    field->max_length=length;
3376
  }
3377
3378
  mysql_field_seek(result,0);
3379
  for (uint row_count=1; (cur= mysql_fetch_row(result)); row_count++)
3380
  {
3381
    if (interrupted_query)
3382
      break;
3383
    mysql_field_seek(result,0);
3384
    tee_fprintf(PAGER, 
3385
		"*************************** %d. row ***************************\n", row_count);
3386
    for (uint off=0; off < mysql_num_fields(result); off++)
3387
    {
3388
      field= mysql_fetch_field(result);
3389
      tee_fprintf(PAGER, "%*s: ",(int) max_length,field->name);
3390
      tee_fprintf(PAGER, "%s\n",cur[off] ? (char*) cur[off] : "NULL");
3391
    }
3392
  }
3393
}
3394
3395
3396
/* print_warnings should be called right after executing a statement */
3397
3398
static void print_warnings()
3399
{
3400
  const char   *query;
3401
  MYSQL_RES    *result;
3402
  MYSQL_ROW    cur;
3403
  my_ulonglong num_rows;
3404
  
3405
  /* Save current error before calling "show warnings" */
3406
  uint error= mysql_errno(&mysql);
3407
3408
  /* Get the warnings */
3409
  query= "show warnings";
3410
  mysql_real_query_for_lazy(query, strlen(query));
3411
  mysql_store_result_for_lazy(&result);
3412
3413
  /* Bail out when no warnings */
3414
  if (!(num_rows= mysql_num_rows(result)))
3415
    goto end;
3416
3417
  cur= mysql_fetch_row(result);
3418
3419
  /*
3420
    Don't print a duplicate of the current error.  It is possible for SHOW
3421
    WARNINGS to return multiple errors with the same code, but different
3422
    messages.  To be safe, skip printing the duplicate only if it is the only
3423
    warning.
3424
  */
133 by Brian Aker
Cleanup of warning/errors.
3425
  if (!cur || (num_rows == 1 && error == (uint) strtoul(cur[1], NULL, 10)))
1 by brian
clean slate
3426
    goto end;
3427
3428
  /* Print the warnings */
3429
  init_pager();
3430
  do
3431
  {
3432
    tee_fprintf(PAGER, "%s (Code %s): %s\n", cur[0], cur[1], cur[2]);
3433
  } while ((cur= mysql_fetch_row(result)));
3434
  end_pager();
3435
3436
end:
3437
  mysql_free_result(result);
3438
}
3439
3440
3441
static const char *array_value(const char **array, char key)
3442
{
3443
  for (; *array; array+= 2)
3444
    if (**array == key)
3445
      return array[1];
3446
  return 0;
3447
}
3448
3449
3450
static void
3451
xmlencode_print(const char *src, uint length)
3452
{
3453
  if (!src)
3454
    tee_fputs("NULL", PAGER);
3455
  else
3456
  {
3457
    for (const char *p = src; *p && length; *p++, length--)
3458
    {
3459
      const char *t;
3460
      if ((t = array_value(xmlmeta, *p)))
3461
	tee_fputs(t, PAGER);
3462
      else
3463
	tee_putc(*p, PAGER);
3464
    }
3465
  }
3466
}
3467
3468
3469
static void
3470
safe_put_field(const char *pos,ulong length)
3471
{
3472
  if (!pos)
3473
    tee_fputs("NULL", PAGER);
3474
  else
3475
  {
3476
    if (opt_raw_data)
3477
      tee_fputs(pos, PAGER);
3478
    else for (const char *end=pos+length ; pos != end ; pos++)
3479
    {
3480
#ifdef USE_MB
3481
      int l;
3482
      if (use_mb(charset_info) &&
3483
          (l = my_ismbchar(charset_info, pos, end)))
3484
      {
3485
	  while (l--)
3486
	    tee_putc(*pos++, PAGER);
3487
	  pos--;
3488
	  continue;
3489
      }
3490
#endif
3491
      if (!*pos)
3492
	tee_fputs("\\0", PAGER); // This makes everything hard
3493
      else if (*pos == '\t')
3494
	tee_fputs("\\t", PAGER); // This would destroy tab format
3495
      else if (*pos == '\n')
3496
	tee_fputs("\\n", PAGER); // This too
3497
      else if (*pos == '\\')
3498
	tee_fputs("\\\\", PAGER);
3499
	else
3500
	tee_putc(*pos, PAGER);
3501
    }
3502
  }
3503
}
3504
3505
3506
static void
3507
print_tab_data(MYSQL_RES *result)
3508
{
3509
  MYSQL_ROW	cur;
3510
  MYSQL_FIELD	*field;
3511
  ulong		*lengths;
3512
3513
  if (opt_silent < 2 && column_names)
3514
  {
3515
    int first=0;
3516
    while ((field = mysql_fetch_field(result)))
3517
    {
3518
      if (first++)
3519
	(void) tee_fputs("\t", PAGER);
3520
      (void) tee_fputs(field->name, PAGER);
3521
    }
3522
    (void) tee_fputs("\n", PAGER);
3523
  }
3524
  while ((cur = mysql_fetch_row(result)))
3525
  {
3526
    lengths=mysql_fetch_lengths(result);
3527
    safe_put_field(cur[0],lengths[0]);
3528
    for (uint off=1 ; off < mysql_num_fields(result); off++)
3529
    {
3530
      (void) tee_fputs("\t", PAGER);
3531
      safe_put_field(cur[off], lengths[off]);
3532
    }
3533
    (void) tee_fputs("\n", PAGER);
3534
  }
3535
}
3536
3537
static int
53.2.4 by Monty Taylor
Changes so that client/ builds cleanly with no warnings.
3538
com_tee(String *buffer __attribute__((__unused__)), char *line )
1 by brian
clean slate
3539
{
3540
  char file_name[FN_REFLEN], *end, *param;
3541
3542
  if (status.batch)
3543
    return 0;
3544
  while (my_isspace(charset_info,*line))
3545
    line++;
3546
  if (!(param = strchr(line, ' '))) // if outfile wasn't given, use the default
3547
  {
3548
    if (!strlen(outfile))
3549
    {
3550
      printf("No previous outfile available, you must give a filename!\n");
3551
      return 0;
3552
    }
3553
    else if (opt_outfile)
3554
    {
3555
      tee_fprintf(stdout, "Currently logging to file '%s'\n", outfile);
3556
      return 0;
3557
    }
3558
    else
3559
      param = outfile;			//resume using the old outfile
3560
  }
3561
3562
  /* eliminate the spaces before the parameters */
3563
  while (my_isspace(charset_info,*param))
3564
    param++;
3565
  end= strmake(file_name, param, sizeof(file_name) - 1);
3566
  /* remove end space from command line */
3567
  while (end > file_name && (my_isspace(charset_info,end[-1]) || 
3568
			     my_iscntrl(charset_info,end[-1])))
3569
    end--;
3570
  end[0]= 0;
3571
  if (end == file_name)
3572
  {
3573
    printf("No outfile specified!\n");
3574
    return 0;
3575
  }
3576
  init_tee(file_name);
3577
  return 0;
3578
}
3579
3580
3581
static int
3582
com_notee(String *buffer __attribute__((unused)),
3583
	  char *line __attribute__((unused)))
3584
{
3585
  if (opt_outfile)
3586
    end_tee();
3587
  tee_fprintf(stdout, "Outfile disabled.\n");
3588
  return 0;
3589
}
3590
3591
/*
3592
  Sorry, this command is not available in Windows.
3593
*/
3594
3595
#ifdef USE_POPEN
3596
static int
3597
com_pager(String *buffer, char *line __attribute__((unused)))
3598
{
3599
  char pager_name[FN_REFLEN], *end, *param;
3600
3601
  if (status.batch)
3602
    return 0;
3603
  /* Skip spaces in front of the pager command */
3604
  while (my_isspace(charset_info, *line))
3605
    line++;
3606
  /* Skip the pager command */
3607
  param= strchr(line, ' ');
3608
  /* Skip the spaces between the command and the argument */
3609
  while (param && my_isspace(charset_info, *param))
3610
    param++;
3611
  if (!param || !strlen(param)) // if pager was not given, use the default
3612
  {
3613
    if (!default_pager_set)
3614
    {
3615
      tee_fprintf(stdout, "Default pager wasn't set, using stdout.\n");
3616
      opt_nopager=1;
3617
      strmov(pager, "stdout");
3618
      PAGER= stdout;
3619
      return 0;
3620
    }
3621
    strmov(pager, default_pager);
3622
  }
3623
  else
3624
  {
3625
    end= strmake(pager_name, param, sizeof(pager_name)-1);
3626
    while (end > pager_name && (my_isspace(charset_info,end[-1]) || 
3627
                                my_iscntrl(charset_info,end[-1])))
3628
      end--;
3629
    end[0]=0;
3630
    strmov(pager, pager_name);
3631
    strmov(default_pager, pager_name);
3632
  }
3633
  opt_nopager=0;
3634
  tee_fprintf(stdout, "PAGER set to '%s'\n", pager);
3635
  return 0;
3636
}
3637
3638
3639
static int
3640
com_nopager(String *buffer __attribute__((unused)),
3641
	    char *line __attribute__((unused)))
3642
{
3643
  strmov(pager, "stdout");
3644
  opt_nopager=1;
3645
  PAGER= stdout;
3646
  tee_fprintf(stdout, "PAGER set to stdout\n");
3647
  return 0;
3648
}
3649
#endif
3650
3651
3652
/*
3653
  Sorry, you can't send the result to an editor in Win32
3654
*/
3655
3656
#ifdef USE_POPEN
3657
static int
3658
com_edit(String *buffer,char *line __attribute__((unused)))
3659
{
3660
  char	filename[FN_REFLEN],buff[160];
3661
  int	fd,tmp;
3662
  const char *editor;
3663
3664
  if ((fd=create_temp_file(filename,NullS,"sql", O_CREAT | O_WRONLY,
3665
			   MYF(MY_WME))) < 0)
3666
    goto err;
3667
  if (buffer->is_empty() && !old_buffer.is_empty())
3668
    (void) my_write(fd,(uchar*) old_buffer.ptr(),old_buffer.length(),
3669
		    MYF(MY_WME));
3670
  else
3671
    (void) my_write(fd,(uchar*) buffer->ptr(),buffer->length(),MYF(MY_WME));
3672
  (void) my_close(fd,MYF(0));
3673
3674
  if (!(editor = (char *)getenv("EDITOR")) &&
3675
      !(editor = (char *)getenv("VISUAL")))
3676
    editor = "vi";
3677
  strxmov(buff,editor," ",filename,NullS);
3678
  (void) system(buff);
3679
15 by brian
Fix for stat, NETWARE removal
3680
  struct stat stat_arg;
3681
  if (stat(filename,&stat_arg))
1 by brian
clean slate
3682
    goto err;
3683
  if ((fd = my_open(filename,O_RDONLY, MYF(MY_WME))) < 0)
3684
    goto err;
3685
  (void) buffer->alloc((uint) stat_arg.st_size);
3686
  if ((tmp=read(fd,(char*) buffer->ptr(),buffer->alloced_length())) >= 0L)
3687
    buffer->length((uint) tmp);
3688
  else
3689
    buffer->length(0);
3690
  (void) my_close(fd,MYF(0));
3691
  (void) my_delete(filename,MYF(MY_WME));
3692
err:
3693
  return 0;
3694
}
3695
#endif
3696
3697
3698
/* If arg is given, exit without errors. This happens on command 'quit' */
3699
3700
static int
3701
com_quit(String *buffer __attribute__((unused)),
3702
	 char *line __attribute__((unused)))
3703
{
3704
  /* let the screen auto close on a normal shutdown */
3705
  status.exit_status=0;
3706
  return 1;
3707
}
3708
3709
static int
3710
com_rehash(String *buffer __attribute__((unused)),
3711
	 char *line __attribute__((unused)))
3712
{
3713
#ifdef HAVE_READLINE
3714
  build_completion_hash(1, 0);
3715
#endif
3716
  return 0;
3717
}
3718
3719
3720
#ifdef USE_POPEN
3721
static int
3722
com_shell(String *buffer, char *line __attribute__((unused)))
3723
{
3724
  char *shell_cmd;
3725
3726
  /* Skip space from line begin */
3727
  while (my_isspace(charset_info, *line))
3728
    line++;
3729
  if (!(shell_cmd = strchr(line, ' ')))
3730
  {
3731
    put_info("Usage: \\! shell-command", INFO_ERROR);
3732
    return -1;
3733
  }
3734
  /*
3735
    The output of the shell command does not
3736
    get directed to the pager or the outfile
3737
  */
3738
  if (system(shell_cmd) == -1)
3739
  {
3740
    put_info(strerror(errno), INFO_ERROR, errno);
3741
    return -1;
3742
  }
3743
  return 0;
3744
}
3745
#endif
3746
3747
3748
static int
3749
com_print(String *buffer,char *line __attribute__((unused)))
3750
{
3751
  tee_puts("--------------", stdout);
3752
  (void) tee_fputs(buffer->c_ptr(), stdout);
3753
  if (!buffer->length() || (*buffer)[buffer->length()-1] != '\n')
3754
    tee_putc('\n', stdout);
3755
  tee_puts("--------------\n", stdout);
3756
  return 0;					/* If empty buffer */
3757
}
3758
3759
	/* ARGSUSED */
3760
static int
3761
com_connect(String *buffer, char *line)
3762
{
3763
  char *tmp, buff[256];
3764
  bool save_rehash= opt_rehash;
3765
  int error;
3766
3767
  bzero(buff, sizeof(buff));
3768
  if (buffer)
3769
  {
3770
    /*
3771
      Two null bytes are needed in the end of buff to allow
3772
      get_arg to find end of string the second time it's called.
3773
    */
3774
    tmp= strmake(buff, line, sizeof(buff)-2);
3775
#ifdef EXTRA_DEBUG
3776
    tmp[1]= 0;
3777
#endif
3778
    tmp= get_arg(buff, 0);
3779
    if (tmp && *tmp)
3780
    {
3781
      my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
3782
      current_db= my_strdup(tmp, MYF(MY_WME));
3783
      tmp= get_arg(buff, 1);
3784
      if (tmp)
3785
      {
3786
	my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
3787
	current_host=my_strdup(tmp,MYF(MY_WME));
3788
      }
3789
    }
3790
    else
3791
    {
3792
      /* Quick re-connect */
3793
      opt_rehash= 0;                            /* purecov: tested */
3794
    }
3795
    buffer->length(0);				// command used
3796
  }
3797
  else
3798
    opt_rehash= 0;
3799
  error=sql_connect(current_host,current_db,current_user,opt_password,0);
3800
  opt_rehash= save_rehash;
3801
3802
  if (connected)
3803
  {
3804
    sprintf(buff,"Connection id:    %lu",mysql_thread_id(&mysql));
3805
    put_info(buff,INFO_INFO);
3806
    sprintf(buff,"Current database: %.128s\n",
3807
	    current_db ? current_db : "*** NONE ***");
3808
    put_info(buff,INFO_INFO);
3809
  }
3810
  return error;
3811
}
3812
3813
53.2.4 by Monty Taylor
Changes so that client/ builds cleanly with no warnings.
3814
static int com_source(String *buffer __attribute__((__unused__)), char *line)
1 by brian
clean slate
3815
{
3816
  char source_name[FN_REFLEN], *end, *param;
3817
  LINE_BUFFER *line_buff;
3818
  int error;
3819
  STATUS old_status;
3820
  FILE *sql_file;
3821
3822
  /* Skip space from file name */
3823
  while (my_isspace(charset_info,*line))
3824
    line++;
3825
  if (!(param = strchr(line, ' ')))		// Skip command name
3826
    return put_info("Usage: \\. <filename> | source <filename>", 
3827
		    INFO_ERROR, 0);
3828
  while (my_isspace(charset_info,*param))
3829
    param++;
3830
  end=strmake(source_name,param,sizeof(source_name)-1);
3831
  while (end > source_name && (my_isspace(charset_info,end[-1]) || 
3832
                               my_iscntrl(charset_info,end[-1])))
3833
    end--;
3834
  end[0]=0;
3835
  unpack_filename(source_name,source_name);
3836
  /* open file name */
3837
  if (!(sql_file = my_fopen(source_name, O_RDONLY | O_BINARY,MYF(0))))
3838
  {
3839
    char buff[FN_REFLEN+60];
3840
    sprintf(buff,"Failed to open file '%s', error: %d", source_name,errno);
3841
    return put_info(buff, INFO_ERROR, 0);
3842
  }
3843
3844
  if (!(line_buff=batch_readline_init(opt_max_allowed_packet+512,sql_file)))
3845
  {
3846
    my_fclose(sql_file,MYF(0));
3847
    return put_info("Can't initialize batch_readline", INFO_ERROR, 0);
3848
  }
3849
3850
  /* Save old status */
3851
  old_status=status;
3852
  bfill((char*) &status,sizeof(status),(char) 0);
3853
3854
  status.batch=old_status.batch;		// Run in batch mode
3855
  status.line_buff=line_buff;
3856
  status.file_name=source_name;
3857
  glob_buffer.length(0);			// Empty command buffer
3858
  error= read_and_execute(false);
3859
  status=old_status;				// Continue as before
3860
  my_fclose(sql_file,MYF(0));
3861
  batch_readline_end(line_buff);
3862
  return error;
3863
}
3864
3865
3866
	/* ARGSUSED */
3867
static int
3868
com_delimiter(String *buffer __attribute__((unused)), char *line)
3869
{
3870
  char buff[256], *tmp;
3871
3872
  strmake(buff, line, sizeof(buff) - 1);
3873
  tmp= get_arg(buff, 0);
3874
3875
  if (!tmp || !*tmp)
3876
  {
3877
    put_info("DELIMITER must be followed by a 'delimiter' character or string",
3878
	     INFO_ERROR);
3879
    return 0;
3880
  }
3881
  else
3882
  {
3883
    if (strstr(tmp, "\\")) 
3884
    {
3885
      put_info("DELIMITER cannot contain a backslash character", INFO_ERROR);
3886
      return 0;
3887
    }
3888
  }
3889
  strmake(delimiter, tmp, sizeof(delimiter) - 1);
3890
  delimiter_length= (int)strlen(delimiter);
3891
  delimiter_str= delimiter;
3892
  return 0;
3893
}
3894
3895
	/* ARGSUSED */
3896
static int
3897
com_use(String *buffer __attribute__((unused)), char *line)
3898
{
3899
  char *tmp, buff[FN_REFLEN + 1];
3900
  int select_db;
3901
3902
  bzero(buff, sizeof(buff));
3903
  strmake(buff, line, sizeof(buff) - 1);
3904
  tmp= get_arg(buff, 0);
3905
  if (!tmp || !*tmp)
3906
  {
3907
    put_info("USE must be followed by a database name", INFO_ERROR);
3908
    return 0;
3909
  }
3910
  /*
3911
    We need to recheck the current database, because it may change
3912
    under our feet, for example if DROP DATABASE or RENAME DATABASE
3913
    (latter one not yet available by the time the comment was written)
3914
  */
3915
  get_current_db();
3916
3917
  if (!current_db || cmp_database(charset_info, current_db,tmp))
3918
  {
3919
    if (one_database)
3920
    {
3921
      skip_updates= 1;
3922
      select_db= 0;    // don't do mysql_select_db()
3923
    }
3924
    else
3925
      select_db= 2;    // do mysql_select_db() and build_completion_hash()
3926
  }
3927
  else
3928
  {
3929
    /*
3930
      USE to the current db specified.
3931
      We do need to send mysql_select_db() to make server
3932
      update database level privileges, which might
3933
      change since last USE (see bug#10979).
3934
      For performance purposes, we'll skip rebuilding of completion hash.
3935
    */
3936
    skip_updates= 0;
3937
    select_db= 1;      // do only mysql_select_db(), without completion
3938
  }
3939
3940
  if (select_db)
3941
  {
3942
    /*
3943
      reconnect once if connection is down or if connection was found to
3944
      be down during query
3945
    */
3946
    if (!connected && reconnect())
3947
      return opt_reconnect ? -1 : 1;                        // Fatal error
3948
    if (mysql_select_db(&mysql,tmp))
3949
    {
3950
      if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR)
3951
        return put_error(&mysql);
3952
3953
      if (reconnect())
3954
        return opt_reconnect ? -1 : 1;                      // Fatal error
3955
      if (mysql_select_db(&mysql,tmp))
3956
        return put_error(&mysql);
3957
    }
3958
    my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
3959
    current_db=my_strdup(tmp,MYF(MY_WME));
3960
#ifdef HAVE_READLINE
3961
    if (select_db > 1)
3962
      build_completion_hash(opt_rehash, 1);
3963
#endif
3964
  }
3965
3966
  put_info("Database changed",INFO_INFO);
3967
  return 0;
3968
}
3969
3970
static int
3971
com_warnings(String *buffer __attribute__((unused)),
3972
   char *line __attribute__((unused)))
3973
{
3974
  show_warnings = 1;
3975
  put_info("Show warnings enabled.",INFO_INFO);
3976
  return 0;
3977
}
3978
3979
static int
3980
com_nowarnings(String *buffer __attribute__((unused)),
3981
   char *line __attribute__((unused)))
3982
{
3983
  show_warnings = 0;
3984
  put_info("Show warnings disabled.",INFO_INFO);
3985
  return 0;
3986
}
3987
3988
/*
3989
  Gets argument from a command on the command line. If get_next_arg is
3990
  not defined, skips the command and returns the first argument. The
3991
  line is modified by adding zero to the end of the argument. If
3992
  get_next_arg is defined, then the function searches for end of string
3993
  first, after found, returns the next argument and adds zero to the
3994
  end. If you ever wish to use this feature, remember to initialize all
3995
  items in the array to zero first.
3996
*/
3997
3998
char *get_arg(char *line, my_bool get_next_arg)
3999
{
4000
  char *ptr, *start;
4001
  my_bool quoted= 0, valid_arg= 0;
4002
  char qtype= 0;
4003
4004
  ptr= line;
4005
  if (get_next_arg)
4006
  {
4007
    for (; *ptr; ptr++) ;
4008
    if (*(ptr + 1))
4009
      ptr++;
4010
  }
4011
  else
4012
  {
4013
    /* skip leading white spaces */
4014
    while (my_isspace(charset_info, *ptr))
4015
      ptr++;
4016
    if (*ptr == '\\') // short command was used
4017
      ptr+= 2;
4018
    else
4019
      while (*ptr &&!my_isspace(charset_info, *ptr)) // skip command
4020
        ptr++;
4021
  }
4022
  if (!*ptr)
4023
    return NullS;
4024
  while (my_isspace(charset_info, *ptr))
4025
    ptr++;
4026
  if (*ptr == '\'' || *ptr == '\"' || *ptr == '`')
4027
  {
4028
    qtype= *ptr;
4029
    quoted= 1;
4030
    ptr++;
4031
  }
4032
  for (start=ptr ; *ptr; ptr++)
4033
  {
4034
    if (*ptr == '\\' && ptr[1]) // escaped character
4035
    {
4036
      // Remove the backslash
4037
      strmov(ptr, ptr+1);
4038
    }
4039
    else if ((!quoted && *ptr == ' ') || (quoted && *ptr == qtype))
4040
    {
4041
      *ptr= 0;
4042
      break;
4043
    }
4044
  }
4045
  valid_arg= ptr != start;
4046
  return valid_arg ? start : NullS;
4047
}
4048
4049
4050
static int
4051
sql_real_connect(char *host,char *database,char *user,char *password,
4052
		 uint silent)
4053
{
4054
  if (connected)
4055
  {
4056
    connected= 0;
4057
    mysql_close(&mysql);
4058
  }
4059
  mysql_init(&mysql);
4060
  if (opt_connect_timeout)
4061
  {
4062
    uint timeout=opt_connect_timeout;
4063
    mysql_options(&mysql,MYSQL_OPT_CONNECT_TIMEOUT,
4064
		  (char*) &timeout);
4065
  }
4066
  if (opt_compress)
4067
    mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
4068
  if (opt_secure_auth)
4069
    mysql_options(&mysql, MYSQL_SECURE_AUTH, (char *) &opt_secure_auth);
4070
  if (using_opt_local_infile)
4071
    mysql_options(&mysql,MYSQL_OPT_LOCAL_INFILE, (char*) &opt_local_infile);
4072
  if (opt_protocol)
4073
    mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
4074
#ifdef HAVE_SMEM
4075
  if (shared_memory_base_name)
4076
    mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
4077
#endif
4078
  if (safe_updates)
4079
  {
4080
    char init_command[100];
4081
    sprintf(init_command,
4082
	    "SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=%lu,SQL_MAX_JOIN_SIZE=%lu",
4083
	    select_limit,max_join_size);
4084
    mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command);
4085
  }
4086
  if (default_charset_used)
4087
    mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
4088
  if (!mysql_real_connect(&mysql, host, user, password,
4089
			  database, opt_mysql_port, opt_mysql_unix_port,
4090
			  connect_flag | CLIENT_MULTI_STATEMENTS))
4091
  {
4092
    if (!silent ||
4093
	(mysql_errno(&mysql) != CR_CONN_HOST_ERROR &&
4094
	 mysql_errno(&mysql) != CR_CONNECTION_ERROR))
4095
    {
4096
      (void) put_error(&mysql);
4097
      (void) fflush(stdout);
4098
      return ignore_errors ? -1 : 1;		// Abort
4099
    }
4100
    return -1;					// Retryable
4101
  }
4102
  connected=1;
4103
#ifndef EMBEDDED_LIBRARY
4104
  mysql.reconnect= debug_info_flag; // We want to know if this happens
4105
#else
4106
  mysql.reconnect= 1;
4107
#endif
4108
#ifdef HAVE_READLINE
4109
  build_completion_hash(opt_rehash, 1);
4110
#endif
4111
  return 0;
4112
}
4113
4114
4115
static int
4116
sql_connect(char *host,char *database,char *user,char *password,uint silent)
4117
{
4118
  bool message=0;
4119
  uint count=0;
4120
  int error;
4121
  for (;;)
4122
  {
4123
    if ((error=sql_real_connect(host,database,user,password,wait_flag)) >= 0)
4124
    {
4125
      if (count)
4126
      {
4127
	tee_fputs("\n", stderr);
4128
	(void) fflush(stderr);
4129
      }
4130
      return error;
4131
    }
4132
    if (!wait_flag)
4133
      return ignore_errors ? -1 : 1;
4134
    if (!message && !silent)
4135
    {
4136
      message=1;
4137
      tee_fputs("Waiting",stderr); (void) fflush(stderr);
4138
    }
4139
    (void) sleep(wait_time);
4140
    if (!silent)
4141
    {
4142
      putc('.',stderr); (void) fflush(stderr);
4143
      count++;
4144
    }
4145
  }
4146
}
4147
4148
4149
4150
static int
4151
com_status(String *buffer __attribute__((unused)),
4152
	   char *line __attribute__((unused)))
4153
{
4154
  const char *status_str;
4155
  char buff[40];
4156
  ulonglong id;
4157
  MYSQL_RES *result;
4158
4159
  tee_puts("--------------", stdout);
4160
  usage(1);					/* Print version */
4161
  if (connected)
4162
  {
4163
    tee_fprintf(stdout, "\nConnection id:\t\t%lu\n",mysql_thread_id(&mysql));
4164
    /* 
4165
      Don't remove "limit 1", 
4166
      it is protection againts SQL_SELECT_LIMIT=0
4167
    */
4168
    if (!mysql_query(&mysql,"select DATABASE(), USER() limit 1") &&
4169
	(result=mysql_use_result(&mysql)))
4170
    {
4171
      MYSQL_ROW cur=mysql_fetch_row(result);
4172
      if (cur)
4173
      {
4174
        tee_fprintf(stdout, "Current database:\t%s\n", cur[0] ? cur[0] : "");
4175
        tee_fprintf(stdout, "Current user:\t\t%s\n", cur[1]);
4176
      }
4177
      mysql_free_result(result);
4178
    } 
4179
      tee_puts("SSL:\t\t\tNot in use", stdout);
4180
  }
4181
  else
4182
  {
4183
    vidattr(A_BOLD);
4184
    tee_fprintf(stdout, "\nNo connection\n");
4185
    vidattr(A_NORMAL);
4186
    return 0;
4187
  }
4188
  if (skip_updates)
4189
  {
4190
    vidattr(A_BOLD);
4191
    tee_fprintf(stdout, "\nAll updates ignored to this database\n");
4192
    vidattr(A_NORMAL);
4193
  }
4194
#ifdef USE_POPEN
4195
  tee_fprintf(stdout, "Current pager:\t\t%s\n", pager);
4196
  tee_fprintf(stdout, "Using outfile:\t\t'%s'\n", opt_outfile ? outfile : "");
4197
#endif
4198
  tee_fprintf(stdout, "Using delimiter:\t%s\n", delimiter);
4199
  tee_fprintf(stdout, "Server version:\t\t%s\n", server_version_string(&mysql));
4200
  tee_fprintf(stdout, "Protocol version:\t%d\n", mysql_get_proto_info(&mysql));
4201
  tee_fprintf(stdout, "Connection:\t\t%s\n", mysql_get_host_info(&mysql));
4202
  if ((id= mysql_insert_id(&mysql)))
4203
    tee_fprintf(stdout, "Insert id:\t\t%s\n", llstr(id, buff));
4204
4205
  /* "limit 1" is protection against SQL_SELECT_LIMIT=0 */
4206
  if (!mysql_query(&mysql,"select @@character_set_client, @@character_set_connection, @@character_set_server, @@character_set_database limit 1") &&
4207
      (result=mysql_use_result(&mysql)))
4208
  {
4209
    MYSQL_ROW cur=mysql_fetch_row(result);
4210
    if (cur)
4211
    {
4212
      tee_fprintf(stdout, "Server characterset:\t%s\n", cur[2] ? cur[2] : "");
4213
      tee_fprintf(stdout, "Db     characterset:\t%s\n", cur[3] ? cur[3] : "");
4214
      tee_fprintf(stdout, "Client characterset:\t%s\n", cur[0] ? cur[0] : "");
4215
      tee_fprintf(stdout, "Conn.  characterset:\t%s\n", cur[1] ? cur[1] : "");
4216
    }
4217
    mysql_free_result(result);
4218
  }
4219
  else
4220
  {
4221
    /* Probably pre-4.1 server */
4222
    tee_fprintf(stdout, "Client characterset:\t%s\n", charset_info->csname);
4223
    tee_fprintf(stdout, "Server characterset:\t%s\n", mysql.charset->csname);
4224
  }
4225
4226
#ifndef EMBEDDED_LIBRARY
4227
  if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || ! mysql.unix_socket)
4228
    tee_fprintf(stdout, "TCP port:\t\t%d\n", mysql.port);
4229
  else
4230
    tee_fprintf(stdout, "UNIX socket:\t\t%s\n", mysql.unix_socket);
4231
  if (mysql.net.compress)
4232
    tee_fprintf(stdout, "Protocol:\t\tCompressed\n");
4233
#endif
4234
4235
  if ((status_str= mysql_stat(&mysql)) && !mysql_error(&mysql)[0])
4236
  {
4237
    ulong sec;
4238
    const char *pos= strchr(status_str,' ');
4239
    /* print label */
4240
    tee_fprintf(stdout, "%.*s\t\t\t", (int) (pos-status_str), status_str);
4241
    if ((status_str= str2int(pos,10,0,LONG_MAX,(long*) &sec)))
4242
    {
4243
      nice_time((double) sec,buff,0);
4244
      tee_puts(buff, stdout);			/* print nice time */
4245
      while (*status_str == ' ')
4246
        status_str++;  /* to next info */
4247
      tee_putc('\n', stdout);
4248
      tee_puts(status_str, stdout);
4249
    }
4250
  }
4251
  if (safe_updates)
4252
  {
4253
    vidattr(A_BOLD);
4254
    tee_fprintf(stdout, "\nNote that you are running in safe_update_mode:\n");
4255
    vidattr(A_NORMAL);
4256
    tee_fprintf(stdout, "\
4257
UPDATEs and DELETEs that don't use a key in the WHERE clause are not allowed.\n\
4258
(One can force an UPDATE/DELETE by adding LIMIT # at the end of the command.)\n\
4259
SELECT has an automatic 'LIMIT %lu' if LIMIT is not used.\n\
4260
Max number of examined row combination in a join is set to: %lu\n\n",
4261
select_limit, max_join_size);
4262
  }
4263
  tee_puts("--------------\n", stdout);
4264
  return 0;
4265
}
4266
4267
static const char *
4268
server_version_string(MYSQL *con)
4269
{
4270
  static char buf[MAX_SERVER_VERSION_LENGTH] = "";
4271
4272
  /* Only one thread calls this, so no synchronization is needed */
4273
  if (buf[0] == '\0')
4274
  {
4275
    char *bufp = buf;
4276
    MYSQL_RES *result;
4277
4278
    bufp= strnmov(buf, mysql_get_server_info(con), sizeof buf);
4279
4280
    /* "limit 1" is protection against SQL_SELECT_LIMIT=0 */
4281
    if (!mysql_query(con, "select @@version_comment limit 1") &&
4282
        (result = mysql_use_result(con)))
4283
    {
4284
      MYSQL_ROW cur = mysql_fetch_row(result);
4285
      if (cur && cur[0])
4286
      {
4287
        bufp = strxnmov(bufp, sizeof buf - (bufp - buf), " ", cur[0], NullS);
4288
      }
4289
      mysql_free_result(result);
4290
    }
4291
4292
    /* str*nmov doesn't guarantee NUL-termination */
4293
    if (bufp == buf + sizeof buf)
4294
      buf[sizeof buf - 1] = '\0';
4295
  }
4296
4297
  return buf;
4298
}
4299
4300
static int
4301
put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate)
4302
{
4303
  FILE *file= (info_type == INFO_ERROR ? stderr : stdout);
4304
  static int inited=0;
4305
4306
  if (status.batch)
4307
  {
4308
    if (info_type == INFO_ERROR)
4309
    {
4310
      (void) fflush(file);
4311
      fprintf(file,"ERROR");
4312
      if (error)
4313
      {
4314
	if (sqlstate)
4315
	  (void) fprintf(file," %d (%s)",error, sqlstate);
4316
        else
4317
	  (void) fprintf(file," %d",error);
4318
      }
4319
      if (status.query_start_line && line_numbers)
4320
      {
4321
	(void) fprintf(file," at line %lu",status.query_start_line);
4322
	if (status.file_name)
4323
	  (void) fprintf(file," in file: '%s'", status.file_name);
4324
      }
4325
      (void) fprintf(file,": %s\n",str);
4326
      (void) fflush(file);
4327
      if (!ignore_errors)
4328
	return 1;
4329
    }
4330
    else if (info_type == INFO_RESULT && verbose > 1)
4331
      tee_puts(str, file);
4332
    if (unbuffered)
4333
      fflush(file);
4334
    return info_type == INFO_ERROR ? -1 : 0;
4335
  }
4336
  if (!opt_silent || info_type == INFO_ERROR)
4337
  {
4338
    if (!inited)
4339
    {
4340
      inited=1;
4341
#ifdef HAVE_SETUPTERM
4342
      (void) setupterm((char *)0, 1, (int *) 0);
4343
#endif
4344
    }
4345
    if (info_type == INFO_ERROR)
4346
    {
4347
      if (!opt_nobeep)
4348
        putchar('\a');		      	/* This should make a bell */
4349
      vidattr(A_STANDOUT);
4350
      if (error)
4351
      {
4352
	if (sqlstate)
4353
          (void) tee_fprintf(file, "ERROR %d (%s): ", error, sqlstate);
4354
        else
4355
          (void) tee_fprintf(file, "ERROR %d: ", error);
4356
      }
4357
      else
4358
        tee_puts("ERROR: ", file);
4359
    }
4360
    else
4361
      vidattr(A_BOLD);
4362
    (void) tee_puts(str, file);
4363
    vidattr(A_NORMAL);
4364
  }
4365
  if (unbuffered)
4366
    fflush(file);
4367
  return info_type == INFO_ERROR ? -1 : 0;
4368
}
4369
4370
4371
static int
4372
put_error(MYSQL *con)
4373
{
4374
  return put_info(mysql_error(con), INFO_ERROR, mysql_errno(con),
4375
		  mysql_sqlstate(con));
4376
}  
4377
4378
4379
static void remove_cntrl(String &buffer)
4380
{
4381
  char *start,*end;
4382
  end=(start=(char*) buffer.ptr())+buffer.length();
4383
  while (start < end && !my_isgraph(charset_info,end[-1]))
4384
    end--;
4385
  buffer.length((uint) (end-start));
4386
}
4387
4388
4389
void tee_fprintf(FILE *file, const char *fmt, ...)
4390
{
4391
  va_list args;
4392
4393
  va_start(args, fmt);
4394
  (void) vfprintf(file, fmt, args);
4395
  va_end(args);
4396
4397
  if (opt_outfile)
4398
  {
4399
    va_start(args, fmt);
4400
    (void) vfprintf(OUTFILE, fmt, args);
4401
    va_end(args);
4402
  }
4403
}
4404
4405
4406
void tee_fputs(const char *s, FILE *file)
4407
{
4408
  fputs(s, file);
4409
  if (opt_outfile)
4410
    fputs(s, OUTFILE);
4411
}
4412
4413
4414
void tee_puts(const char *s, FILE *file)
4415
{
4416
  fputs(s, file);
4417
  fputc('\n', file);
4418
  if (opt_outfile)
4419
  {
4420
    fputs(s, OUTFILE);
4421
    fputc('\n', OUTFILE);
4422
  }
4423
}
4424
4425
void tee_putc(int c, FILE *file)
4426
{
4427
  putc(c, file);
4428
  if (opt_outfile)
4429
    putc(c, OUTFILE);
4430
}
4431
4432
#include <sys/times.h>
4433
#ifdef _SC_CLK_TCK				// For mit-pthreads
4434
#undef CLOCKS_PER_SEC
4435
#define CLOCKS_PER_SEC (sysconf(_SC_CLK_TCK))
4436
#endif
4437
4438
static ulong start_timer(void)
4439
{
4440
  struct tms tms_tmp;
4441
  return times(&tms_tmp);
4442
}
4443
4444
4445
/** 
4446
  Write as many as 52+1 bytes to buff, in the form of a legible duration of time.
4447
4448
  len("4294967296 days, 23 hours, 59 minutes, 60.00 seconds")  ->  52
4449
*/
4450
static void nice_time(double sec,char *buff,bool part_second)
4451
{
4452
  ulong tmp;
4453
  if (sec >= 3600.0*24)
4454
  {
4455
    tmp=(ulong) floor(sec/(3600.0*24));
4456
    sec-=3600.0*24*tmp;
4457
    buff=int10_to_str((long) tmp, buff, 10);
4458
    buff=strmov(buff,tmp > 1 ? " days " : " day ");
4459
  }
4460
  if (sec >= 3600.0)
4461
  {
4462
    tmp=(ulong) floor(sec/3600.0);
4463
    sec-=3600.0*tmp;
4464
    buff=int10_to_str((long) tmp, buff, 10);
4465
    buff=strmov(buff,tmp > 1 ? " hours " : " hour ");
4466
  }
4467
  if (sec >= 60.0)
4468
  {
4469
    tmp=(ulong) floor(sec/60.0);
4470
    sec-=60.0*tmp;
4471
    buff=int10_to_str((long) tmp, buff, 10);
4472
    buff=strmov(buff," min ");
4473
  }
4474
  if (part_second)
4475
    sprintf(buff,"%.2f sec",sec);
4476
  else
4477
    sprintf(buff,"%d sec",(int) sec);
4478
}
4479
4480
4481
static void end_timer(ulong start_time,char *buff)
4482
{
4483
  nice_time((double) (start_timer() - start_time) /
4484
	    CLOCKS_PER_SEC,buff,1);
4485
}
4486
4487
4488
static void mysql_end_timer(ulong start_time,char *buff)
4489
{
4490
  buff[0]=' ';
4491
  buff[1]='(';
4492
  end_timer(start_time,buff+2);
4493
  strmov(strend(buff),")");
4494
}
4495
4496
static const char* construct_prompt()
4497
{
4498
  processed_prompt.free();			// Erase the old prompt
4499
  time_t  lclock = time(NULL);			// Get the date struct
4500
  struct tm *t = localtime(&lclock);
4501
4502
  /* parse thru the settings for the prompt */
4503
  for (char *c = current_prompt; *c ; *c++)
4504
  {
4505
    if (*c != PROMPT_CHAR)
4506
	processed_prompt.append(*c);
4507
    else
4508
    {
4509
      switch (*++c) {
4510
      case '\0':
4511
	c--;			// stop it from going beyond if ends with %
4512
	break;
4513
      case 'c':
4514
	add_int_to_prompt(++prompt_counter);
4515
	break;
4516
      case 'v':
4517
	if (connected)
4518
	  processed_prompt.append(mysql_get_server_info(&mysql));
4519
	else
4520
	  processed_prompt.append("not_connected");
4521
	break;
4522
      case 'd':
4523
	processed_prompt.append(current_db ? current_db : "(none)");
4524
	break;
4525
      case 'h':
4526
      {
4527
	const char *prompt;
4528
	prompt= connected ? mysql_get_host_info(&mysql) : "not_connected";
4529
	if (strstr(prompt, "Localhost"))
4530
	  processed_prompt.append("localhost");
4531
	else
4532
	{
4533
	  const char *end=strcend(prompt,' ');
4534
	  processed_prompt.append(prompt, (uint) (end-prompt));
4535
	}
4536
	break;
4537
      }
4538
      case 'p':
4539
      {
4540
#ifndef EMBEDDED_LIBRARY
4541
	if (!connected)
4542
	{
4543
	  processed_prompt.append("not_connected");
4544
	  break;
4545
	}
4546
4547
	const char *host_info = mysql_get_host_info(&mysql);
4548
	if (strstr(host_info, "memory")) 
4549
	{
4550
		processed_prompt.append( mysql.host );
4551
	}
4552
	else if (strstr(host_info,"TCP/IP") ||
4553
	    !mysql.unix_socket)
4554
	  add_int_to_prompt(mysql.port);
4555
	else
4556
	{
4557
	  char *pos=strrchr(mysql.unix_socket,'/');
4558
 	  processed_prompt.append(pos ? pos+1 : mysql.unix_socket);
4559
	}
4560
#endif
4561
      }
4562
	break;
4563
      case 'U':
4564
	if (!full_username)
4565
	  init_username();
4566
        processed_prompt.append(full_username ? full_username :
4567
                                (current_user ?  current_user : "(unknown)"));
4568
	break;
4569
      case 'u':
4570
	if (!full_username)
4571
	  init_username();
4572
        processed_prompt.append(part_username ? part_username :
4573
                                (current_user ?  current_user : "(unknown)"));
4574
	break;
4575
      case PROMPT_CHAR:
4576
	processed_prompt.append(PROMPT_CHAR);
4577
	break;
4578
      case 'n':
4579
	processed_prompt.append('\n');
4580
	break;
4581
      case ' ':
4582
      case '_':
4583
	processed_prompt.append(' ');
4584
	break;
4585
      case 'R':
4586
	if (t->tm_hour < 10)
4587
	  processed_prompt.append('0');
4588
	add_int_to_prompt(t->tm_hour);
4589
	break;
4590
      case 'r':
4591
	int getHour;
4592
	getHour = t->tm_hour % 12;
4593
	if (getHour == 0)
4594
	  getHour=12;
4595
	if (getHour < 10)
4596
	  processed_prompt.append('0');
4597
	add_int_to_prompt(getHour);
4598
	break;
4599
      case 'm':
4600
	if (t->tm_min < 10)
4601
	  processed_prompt.append('0');
4602
	add_int_to_prompt(t->tm_min);
4603
	break;
4604
      case 'y':
4605
	int getYear;
4606
	getYear = t->tm_year % 100;
4607
	if (getYear < 10)
4608
	  processed_prompt.append('0');
4609
	add_int_to_prompt(getYear);
4610
	break;
4611
      case 'Y':
4612
	add_int_to_prompt(t->tm_year+1900);
4613
	break;
4614
      case 'D':
4615
	char* dateTime;
4616
	dateTime = ctime(&lclock);
4617
	processed_prompt.append(strtok(dateTime,"\n"));
4618
	break;
4619
      case 's':
4620
	if (t->tm_sec < 10)
4621
	  processed_prompt.append('0');
4622
	add_int_to_prompt(t->tm_sec);
4623
	break;
4624
      case 'w':
4625
	processed_prompt.append(day_names[t->tm_wday]);
4626
	break;
4627
      case 'P':
4628
	processed_prompt.append(t->tm_hour < 12 ? "am" : "pm");
4629
	break;
4630
      case 'o':
4631
	add_int_to_prompt(t->tm_mon+1);
4632
	break;
4633
      case 'O':
4634
	processed_prompt.append(month_names[t->tm_mon]);
4635
	break;
4636
      case '\'':
4637
	processed_prompt.append("'");
4638
	break;
4639
      case '"':
4640
	processed_prompt.append('"');
4641
	break;
4642
      case 'S':
4643
	processed_prompt.append(';');
4644
	break;
4645
      case 't':
4646
	processed_prompt.append('\t');
4647
	break;
4648
      case 'l':
4649
	processed_prompt.append(delimiter_str);
4650
	break;
4651
      default:
4652
	processed_prompt.append(c);
4653
      }
4654
    }
4655
  }
4656
  processed_prompt.append('\0');
4657
  return processed_prompt.ptr();
4658
}
4659
4660
4661
static void add_int_to_prompt(int toadd)
4662
{
4663
  char buffer[16];
4664
  int10_to_str(toadd,buffer,10);
4665
  processed_prompt.append(buffer);
4666
}
4667
4668
static void init_username()
4669
{
4670
  my_free(full_username,MYF(MY_ALLOW_ZERO_PTR));
4671
  my_free(part_username,MYF(MY_ALLOW_ZERO_PTR));
4672
4673
  MYSQL_RES *result;
4674
  if (!mysql_query(&mysql,"select USER()") &&
4675
      (result=mysql_use_result(&mysql)))
4676
  {
4677
    MYSQL_ROW cur=mysql_fetch_row(result);
4678
    full_username=my_strdup(cur[0],MYF(MY_WME));
4679
    part_username=my_strdup(strtok(cur[0],"@"),MYF(MY_WME));
4680
    (void) mysql_fetch_row(result);		// Read eof
4681
  }
4682
}
4683
53.2.4 by Monty Taylor
Changes so that client/ builds cleanly with no warnings.
4684
static int com_prompt(String *buffer __attribute__((__unused__)), char *line)
1 by brian
clean slate
4685
{
4686
  char *ptr=strchr(line, ' ');
4687
  prompt_counter = 0;
4688
  my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR));
4689
  current_prompt=my_strdup(ptr ? ptr+1 : default_prompt,MYF(MY_WME));
4690
  if (!ptr)
4691
    tee_fprintf(stdout, "Returning to default PROMPT of %s\n", default_prompt);
4692
  else
4693
    tee_fprintf(stdout, "PROMPT set to '%s'\n", current_prompt);
4694
  return 0;
4695
}
4696
4697
#ifndef EMBEDDED_LIBRARY
4698
/* Keep sql_string library happy */
4699
4700
void *sql_alloc(size_t Size)
4701
{
4702
  return my_malloc(Size,MYF(MY_WME));
4703
}
4704
4705
void sql_element_free(void *ptr)
4706
{
4707
  my_free(ptr,MYF(0));
4708
}
4709
#endif /* EMBEDDED_LIBRARY */