~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to client/drizzle.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

Show diffs side-by-side

added added

removed removed

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