~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/mysql.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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