Drizzled Public API Documentation

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