Drizzled Public API Documentation

drizzle.cc
00001 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2010 Vijay Samuel
00005  *  Copyright (C) 2008 MySQL
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020  */
00021 
00022 /* drizzle command tool
00023  * Commands compatible with mSQL by David J. Hughes
00024  *
00025  * Written by:
00026  *   Michael 'Monty' Widenius
00027  *   Andi Gutmans  <andi@zend.com>
00028  *   Zeev Suraski  <zeev@zend.com>
00029  *   Jani Tolonen  <jani@mysql.com>
00030  *   Matt Wagner   <matt@mysql.com>
00031  *   Jeremy Cole   <jcole@mysql.com>
00032  *   Tonu Samuel   <tonu@mysql.com>
00033  *   Harrison Fisk <harrison@mysql.com>
00034  *
00035  **/
00036 
00037 #include <config.h>
00038 #include <libdrizzle-2.0/libdrizzle.h>
00039 
00040 #include "server_detect.h"
00041 #include "get_password.h"
00042 
00043 #include <boost/date_time/posix_time/posix_time.hpp>
00044 
00045 #include <cerrno>
00046 #include <string>
00047 #include <drizzled/gettext.h>
00048 #include <iostream>
00049 #include <fstream>
00050 #include <map>
00051 #include <algorithm>
00052 #include <limits.h>
00053 #include <cassert>
00054 #include <stdarg.h>
00055 #include <math.h>
00056 #include <memory>
00057 #include <client/linebuffer.h>
00058 #include <signal.h>
00059 #include <sys/ioctl.h>
00060 #include <drizzled/configmake.h>
00061 #include <drizzled/utf8/utf8.h>
00062 #include <cstdlib>
00063 
00064 #if defined(HAVE_CURSES_H) && defined(HAVE_TERM_H)
00065 #include <curses.h>
00066 #ifdef __sun
00067 #undef clear
00068 #undef erase
00069 #endif
00070 #include <term.h>
00071 #else
00072 #if defined(HAVE_TERMIOS_H)
00073 #include <termios.h>
00074 #include <unistd.h>
00075 #elif defined(HAVE_TERMBITS_H)
00076 #include <termbits.h>
00077 #elif defined(HAVE_ASM_TERMBITS_H) && (!defined __GLIBC__ || !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ > 0))
00078 #include <asm/termbits.h>    // Standard linux
00079 #endif
00080 #if defined(HAVE_TERMCAP_H)
00081 #include <termcap.h>
00082 #else
00083 #ifdef HAVE_CURSES_H
00084 #include <curses.h>
00085 #endif
00086 #undef SYSV        // hack to avoid syntax error
00087 #ifdef HAVE_TERM_H
00088 #include <term.h>
00089 #endif
00090 #endif
00091 #endif
00092 
00093 #ifdef HAVE_LIBREADLINE
00094 #  if defined(HAVE_READLINE_READLINE_H)
00095 #    include <readline/readline.h>
00096 #  elif defined(HAVE_READLINE_H)
00097 #    include <readline.h>
00098 #  else /* !defined(HAVE_READLINE_H) */
00099 extern char *readline ();
00100 #  endif /* !defined(HAVE_READLINE_H) */
00101 char *cmdline = NULL;
00102 #else /* !defined(HAVE_READLINE_READLINE_H) */
00103   /* no readline */
00104 #  error Readline Required
00105 #endif /* HAVE_LIBREADLINE */
00106 
00107 #ifdef HAVE_READLINE_HISTORY
00108 #  if defined(HAVE_READLINE_HISTORY_H)
00109 #    include <readline/history.h>
00110 #  elif defined(HAVE_HISTORY_H)
00111 #    include <history.h>
00112 #  else /* !defined(HAVE_HISTORY_H) */
00113 extern void add_history ();
00114 extern int write_history ();
00115 extern int read_history ();
00116 #  endif /* defined(HAVE_READLINE_HISTORY_H) */
00117     /* no history */
00118 #endif /* HAVE_READLINE_HISTORY */
00119 
00123 #ifndef HAVE_RL_COMPLETION
00124 typedef char **rl_completion_func_t(const char *, int, int);
00125 #define rl_completion_matches(str, func) \
00126   completion_matches((char *)str, (CPFunction *)func)
00127 #endif
00128 
00129 #ifdef HAVE_RL_COMPENTRY
00130 # ifdef HAVE_WORKING_RL_COMPENTRY
00131 typedef rl_compentry_func_t drizzle_compentry_func_t;
00132 # else
00133 /* Snow Leopard ships an rl_compentry which cannot be assigned to
00134  * rl_completion_entry_function. We must undo the complete and total
00135  * ass-bagery.
00136  */
00137 typedef Function drizzle_compentry_func_t;
00138 # endif
00139 #else
00140 typedef Function drizzle_compentry_func_t;
00141 #endif
00142 
00143 #if defined(HAVE_LOCALE_H)
00144 #include <locale.h>
00145 #endif
00146 
00147 
00148 
00149 #if !defined(HAVE_VIDATTR)
00150 #undef vidattr
00151 #define vidattr(A) {}      // Can't get this to work
00152 #endif
00153 #include <boost/program_options.hpp>
00154 #include <boost/scoped_ptr.hpp>
00155 #include <drizzled/program_options/config_file.h>
00156 
00157 #include "user_detect.h"
00158 
00159 using namespace std;
00160 namespace po=boost::program_options;
00161 namespace dpo=drizzled::program_options;
00162 
00163 /* Don't try to make a nice table if the data is too big */
00164 const uint32_t MAX_COLUMN_LENGTH= 1024;
00165 
00166 /* Buffer to hold 'version' and 'version_comment' */
00167 const int MAX_SERVER_VERSION_LENGTH= 128;
00168 
00169 /* Options used during connect */
00170 drizzle_con_options_t global_con_options= DRIZZLE_CON_NONE;
00171 
00172 #define PROMPT_CHAR '\\'
00173 
00174 class Status
00175 {
00176 public:
00177 
00178   Status(int in_exit_status, 
00179          uint32_t in_query_start_line,
00180          char *in_file_name,
00181          LineBuffer *in_line_buff,
00182          bool in_batch,
00183          bool in_add_to_history)
00184     :
00185     exit_status(in_exit_status),
00186     query_start_line(in_query_start_line),
00187     file_name(in_file_name),
00188     line_buff(in_line_buff),
00189     batch(in_batch),
00190     add_to_history(in_add_to_history)
00191     {}
00192 
00193   Status() :
00194     exit_status(0),
00195     query_start_line(0),
00196     file_name(NULL),
00197     line_buff(NULL),
00198     batch(false),        
00199     add_to_history(false)
00200   {}
00201   
00202   int getExitStatus() const
00203   {
00204     return exit_status;
00205   }
00206 
00207   uint32_t getQueryStartLine() const
00208   {
00209     return query_start_line;
00210   }
00211 
00212   const char *getFileName() const
00213   {
00214     return file_name;
00215   }
00216 
00217   LineBuffer *getLineBuff() const
00218   {
00219     return line_buff;
00220   }
00221 
00222   bool getBatch() const
00223   {
00224     return batch;
00225   }
00226 
00227   bool getAddToHistory() const
00228   {
00229     return add_to_history;
00230   }
00231 
00232   void setExitStatus(int in_exit_status)
00233   {
00234     exit_status= in_exit_status;
00235   }
00236 
00237   void setQueryStartLine(uint32_t in_query_start_line)
00238   {
00239     query_start_line= in_query_start_line;
00240   }
00241 
00242   void setFileName(char *in_file_name)
00243   {
00244     file_name= in_file_name;
00245   }
00246 
00247   void setLineBuff(int max_size, FILE *file=NULL)
00248   {
00249     line_buff= new LineBuffer(max_size, file);
00250   }
00251 
00252   void setLineBuff(LineBuffer *in_line_buff)
00253   {
00254     line_buff= in_line_buff;
00255   }
00256 
00257   void setBatch(bool in_batch)
00258   {
00259     batch= in_batch;
00260   }
00261 
00262   void setAddToHistory(bool in_add_to_history)
00263   {
00264     add_to_history= in_add_to_history;
00265   }
00266 
00267 private:
00268   int exit_status;
00269   uint32_t query_start_line;
00270   char *file_name;
00271   LineBuffer *line_buff;
00272   bool batch,add_to_history;
00273 }; 
00274 
00275 static map<string, string>::iterator completion_iter;
00276 static map<string, string>::iterator completion_end;
00277 static map<string, string> completion_map;
00278 static string completion_string;
00279 
00280 
00281 enum enum_info_type { INFO_INFO,INFO_ERROR,INFO_RESULT};
00282 typedef enum enum_info_type INFO_TYPE;
00283 
00284 static drizzle_st *drizzle= NULL;      /* The library handle */
00285 static drizzle_con_st *con= NULL;      /* The connection */
00286 static bool ignore_errors= false, quick= false,
00287   connected= false, opt_raw_data= false, unbuffered= false,
00288   output_tables= false, opt_rehash= true, skip_updates= false,
00289   safe_updates= false, one_database= false,
00290   opt_shutdown= false, opt_ping= false,
00291   vertical= false, line_numbers= true, column_names= true,
00292   opt_nopager= true, opt_outfile= false, named_cmds= false,
00293   opt_nobeep= false, opt_reconnect= true,
00294   opt_secure_auth= false,
00295   default_pager_set= false, opt_sigint_ignore= false,
00296   auto_vertical_output= false,
00297   show_warnings= false, executing_query= false, interrupted_query= false,
00298   use_drizzle_protocol= false, opt_local_infile;
00299 static uint32_t opt_kill= 0;
00300 static uint32_t show_progress_size= 0;
00301 static bool column_types_flag;
00302 static bool preserve_comments= false;
00303 static uint32_t opt_max_input_line;
00304 static uint32_t opt_drizzle_port= 0;
00305 static int  opt_silent, verbose= 0;
00306 static char *histfile;
00307 static char *histfile_tmp;
00308 static string *glob_buffer;
00309 static string *processed_prompt= NULL;
00310 static char *default_prompt= NULL;
00311 static char *full_username= NULL,*part_username= NULL;
00312 static Status status;
00313 static uint32_t select_limit;
00314 static uint32_t max_join_size;
00315 static uint32_t opt_connect_timeout= 0;
00316 static ServerDetect::server_type server_type= ServerDetect::SERVER_UNKNOWN_FOUND;
00317 std::string current_db,
00318   delimiter_str,  
00319   current_host,
00320   current_prompt,
00321   current_user,
00322   opt_verbose,
00323   current_password,
00324   opt_password,
00325   opt_protocol;
00326 
00327 static const char* get_day_name(int day_of_week)
00328 {
00329   switch(day_of_week)
00330   {
00331   case 0:
00332     return _("Sun");
00333   case 1:
00334     return _("Mon");
00335   case 2:
00336     return _("Tue");
00337   case 3:
00338     return _("Wed");
00339   case 4:
00340     return _("Thu");
00341   case 5:
00342     return _("Fri");
00343   case 6:
00344     return _("Sat");
00345   }
00346 
00347   return NULL;
00348 }
00349 
00350 static const char* get_month_name(int month)
00351 {
00352   switch(month)
00353   {
00354   case 0:
00355     return _("Jan");
00356   case 1:
00357     return _("Feb");
00358   case 2:
00359     return _("Mar");
00360   case 3:
00361     return _("Apr");
00362   case 4:
00363     return _("May");
00364   case 5:
00365     return _("Jun");
00366   case 6:
00367     return _("Jul");
00368   case 7:
00369     return _("Aug");
00370   case 8:
00371     return _("Sep");
00372   case 9:
00373     return _("Oct");
00374   case 10:
00375     return _("Nov");
00376   case 11:
00377     return _("Dec");
00378   }
00379 
00380   return NULL;
00381 }
00382 
00383 /* @TODO: Remove this */
00384 #define FN_REFLEN 512
00385 
00386 static string default_pager("");
00387 static string pager("");
00388 static string outfile("");
00389 static FILE *PAGER, *OUTFILE;
00390 static uint32_t prompt_counter;
00391 static const char *delimiter= NULL;
00392 static uint32_t delimiter_length= 1;
00393 unsigned short terminal_width= 80;
00394 
00395 int drizzleclient_real_query_for_lazy(const char *buf, size_t length, drizzle_result_st *result, uint32_t *error_code);
00396 int drizzleclient_store_result_for_lazy(drizzle_result_st *result);
00397 
00398 void tee_fprintf(FILE *file, const char *fmt, ...);
00399 void tee_fputs(const char *s, FILE *file);
00400 void tee_puts(const char *s, FILE *file);
00401 void tee_putc(int c, FILE *file);
00402 static void tee_print_sized_data(const char *, unsigned int, unsigned int, bool);
00403 /* The names of functions that actually do the manipulation. */
00404 static int process_options(void);
00405 static int com_quit(string *str,const char*),
00406   com_go(string *str,const char*), com_ego(string *str,const char*),
00407   com_print(string *str,const char*),
00408   com_help(string *str,const char*), com_clear(string *str,const char*),
00409   com_connect(string *str,const char*), com_status(string *str,const char*),
00410   com_use(string *str,const char*), com_source(string *str, const char*),
00411   com_shutdown(string *str,const char*),
00412   com_rehash(string *str, const char*), com_tee(string *str, const char*),
00413   com_notee(string *str, const char*),
00414   com_prompt(string *str, const char*), com_delimiter(string *str, const char*),
00415   com_warnings(string *str, const char*), com_nowarnings(string *str, const char*),
00416   com_nopager(string *str, const char*), com_pager(string *str, const char*);
00417 
00418 static int read_and_execute(bool interactive);
00419 static int sql_connect(const string &host, const string &database, const string &user, const string &password);
00420 static const char *server_version_string(drizzle_con_st *con);
00421 static int put_info(const char *str,INFO_TYPE info,uint32_t error,
00422                     const char *sql_state);
00423 static int put_error(drizzle_con_st *con, drizzle_result_st *res);
00424 static void safe_put_field(const char *pos,uint32_t length);
00425 static void init_pager(void);
00426 static void end_pager(void);
00427 static void init_tee(const char *);
00428 static void end_tee(void);
00429 static const char* construct_prompt(void);
00430 static char *get_arg(char *line, bool get_next_arg);
00431 static void init_username(void);
00432 static void add_int_to_prompt(int toadd);
00433 static int get_result_width(drizzle_result_st *res);
00434 static int get_field_disp_length(drizzle_column_st * field);
00435 static const char * strcont(const char *str, const char *set);
00436 
00437 /* A class which contains information on the commands this program
00438    can understand. */
00439 class Commands
00440 {
00441 private:
00442   const char *name;        /* User printable name of the function. */
00443   char cmd_char;        /* msql command character */
00444 public:
00445   Commands(const char *in_name,
00446            char in_cmd_char,
00447            int (*in_func)(string *str,const char *name),
00448            bool in_takes_params,
00449            const char *in_doc) :
00450     name(in_name),
00451     cmd_char(in_cmd_char),
00452     func(in_func),
00453     takes_params(in_takes_params),
00454     doc(in_doc)
00455   {}
00456 
00457   Commands() :
00458     name(),
00459     cmd_char(),
00460     func(NULL),
00461     takes_params(false),
00462     doc()
00463   {}
00464 
00465   int (*func)(string *str,const char *);/* Function to call to do the job. */
00466 
00467   const char *getName() const
00468   {
00469     return name;
00470   }
00471 
00472   char getCmdChar() const
00473   {
00474     return cmd_char;
00475   }
00476 
00477   bool getTakesParams() const
00478   {
00479     return takes_params;
00480   }
00481 
00482   const char *getDoc() const
00483   {
00484     return doc;
00485   }
00486 
00487   void setName(const char *in_name)
00488   {
00489      name= in_name;
00490   }
00491 
00492   void setCmdChar(char in_cmd_char)
00493   {
00494     cmd_char= in_cmd_char;
00495   }
00496 
00497   void setTakesParams(bool in_takes_params)
00498   {
00499     takes_params= in_takes_params;
00500   }
00501 
00502   void setDoc(const char *in_doc)
00503   {
00504     doc= in_doc;
00505   }
00506 
00507 private:
00508   bool takes_params;        /* Max parameters for command */
00509   const char *doc;        /* Documentation for this function.  */
00510 }; 
00511 
00512 
00513 static Commands commands[] = {
00514   Commands( "?",      '?', com_help,   0, N_("Synonym for `help'.") ),
00515   Commands( "clear",  'c', com_clear,  0, N_("Clear command.")),
00516   Commands( "connect",'r', com_connect,1,
00517     N_("Reconnect to the server. Optional arguments are db and host.")),
00518   Commands( "delimiter", 'd', com_delimiter,    1,
00519     N_("Set statement delimiter. NOTE: Takes the rest of the line as new delimiter.") ),
00520   Commands( "ego",    'G', com_ego,    0,
00521     N_("Send command to drizzle server, display result vertically.")),
00522   Commands( "exit",   'q', com_quit,   0, N_("Exit drizzle. Same as quit.")),
00523   Commands( "go",     'g', com_go,     0, N_("Send command to drizzle server.") ),
00524   Commands( "help",   'h', com_help,   0, N_("Display this help.") ),
00525   Commands( "nopager",'n', com_nopager,0, N_("Disable pager, print to stdout.") ),
00526   Commands( "notee",  't', com_notee,  0, N_("Don't write into outfile.") ),
00527   Commands( "pager",  'P', com_pager,  1,
00528     N_("Set PAGER [to_pager]. Print the query results via PAGER.") ),
00529   Commands( "print",  'p', com_print,  0, N_("Print current command.") ),
00530   Commands( "prompt", 'R', com_prompt, 1, N_("Change your drizzle prompt.")),
00531   Commands( "quit",   'q', com_quit,   0, N_("Quit drizzle.") ),
00532   Commands( "rehash", '#', com_rehash, 0, N_("Rebuild completion hash.") ),
00533   Commands( "source", '.', com_source, 1,
00534     N_("Execute an SQL script file. Takes a file name as an argument.")),
00535   Commands( "status", 's', com_status, 0, N_("Get status information from the server.")),
00536   Commands( "tee",    'T', com_tee,    1,
00537     N_("Set outfile [to_outfile]. Append everything into given outfile.") ),
00538   Commands( "use",    'u', com_use,    1,
00539     N_("Use another schema. Takes schema name as argument.") ),
00540   Commands( "shutdown",    'Q', com_shutdown,    false,
00541     N_("Shutdown the instance you are connected too.") ),
00542   Commands( "warnings", 'W', com_warnings,  false,
00543     N_("Show warnings after every statement.") ),
00544   Commands( "nowarning", 'w', com_nowarnings, 0,
00545     N_("Don't show warnings after every statement.") ),
00546   /* Get bash-like expansion for some commands */
00547   Commands( "create table",     0, 0, 0, ""),
00548   Commands( "create database",  0, 0, 0, ""),
00549   Commands( "show databases",   0, 0, 0, ""),
00550   Commands( "show fields from", 0, 0, 0, ""),
00551   Commands( "show keys from",   0, 0, 0, ""),
00552   Commands( "show tables",      0, 0, 0, ""),
00553   Commands( "load data from",   0, 0, 0, ""),
00554   Commands( "alter table",      0, 0, 0, ""),
00555   Commands( "set option",       0, 0, 0, ""),
00556   Commands( "lock tables",      0, 0, 0, ""),
00557   Commands( "unlock tables",    0, 0, 0, ""),
00558   /* generated 2006-12-28.  Refresh occasionally from lexer. */
00559   Commands( "ACTION", 0, 0, 0, ""),
00560   Commands( "ADD", 0, 0, 0, ""),
00561   Commands( "AFTER", 0, 0, 0, ""),
00562   Commands( "AGAINST", 0, 0, 0, ""),
00563   Commands( "AGGREGATE", 0, 0, 0, ""),
00564   Commands( "ALL", 0, 0, 0, ""),
00565   Commands( "ALGORITHM", 0, 0, 0, ""),
00566   Commands( "ALTER", 0, 0, 0, ""),
00567   Commands( "ANALYZE", 0, 0, 0, ""),
00568   Commands( "AND", 0, 0, 0, ""),
00569   Commands( "ANY", 0, 0, 0, ""),
00570   Commands( "AS", 0, 0, 0, ""),
00571   Commands( "ASC", 0, 0, 0, ""),
00572   Commands( "ASCII", 0, 0, 0, ""),
00573   Commands( "ASENSITIVE", 0, 0, 0, ""),
00574   Commands( "AUTO_INCREMENT", 0, 0, 0, ""),
00575   Commands( "AVG", 0, 0, 0, ""),
00576   Commands( "AVG_ROW_LENGTH", 0, 0, 0, ""),
00577   Commands( "BEFORE", 0, 0, 0, ""),
00578   Commands( "BEGIN", 0, 0, 0, ""),
00579   Commands( "BETWEEN", 0, 0, 0, ""),
00580   Commands( "BIGINT", 0, 0, 0, ""),
00581   Commands( "BINARY", 0, 0, 0, ""),
00582   Commands( "BIT", 0, 0, 0, ""),
00583   Commands( "BLOB", 0, 0, 0, ""),
00584   Commands( "BOOL", 0, 0, 0, ""),
00585   Commands( "BOOLEAN", 0, 0, 0, ""),
00586   Commands( "BOTH", 0, 0, 0, ""),
00587   Commands( "BTREE", 0, 0, 0, ""),
00588   Commands( "BY", 0, 0, 0, ""),
00589   Commands( "BYTE", 0, 0, 0, ""),
00590   Commands( "CACHE", 0, 0, 0, ""),
00591   Commands( "CALL", 0, 0, 0, ""),
00592   Commands( "CASCADE", 0, 0, 0, ""),
00593   Commands( "CASCADED", 0, 0, 0, ""),
00594   Commands( "CASE", 0, 0, 0, ""),
00595   Commands( "CHAIN", 0, 0, 0, ""),
00596   Commands( "CHANGE", 0, 0, 0, ""),
00597   Commands( "CHANGED", 0, 0, 0, ""),
00598   Commands( "CHAR", 0, 0, 0, ""),
00599   Commands( "CHARACTER", 0, 0, 0, ""),
00600   Commands( "CHECK", 0, 0, 0, ""),
00601   Commands( "CHECKSUM", 0, 0, 0, ""),
00602   Commands( "CLIENT", 0, 0, 0, ""),
00603   Commands( "CLOSE", 0, 0, 0, ""),
00604   Commands( "COLLATE", 0, 0, 0, ""),
00605   Commands( "COLLATION", 0, 0, 0, ""),
00606   Commands( "COLUMN", 0, 0, 0, ""),
00607   Commands( "COLUMNS", 0, 0, 0, ""),
00608   Commands( "COMMENT", 0, 0, 0, ""),
00609   Commands( "COMMIT", 0, 0, 0, ""),
00610   Commands( "COMMITTED", 0, 0, 0, ""),
00611   Commands( "COMPACT", 0, 0, 0, ""),
00612   Commands( "COMPRESSED", 0, 0, 0, ""),
00613   Commands( "CONCURRENT", 0, 0, 0, ""),
00614   Commands( "CONDITION", 0, 0, 0, ""),
00615   Commands( "CONNECTION", 0, 0, 0, ""),
00616   Commands( "CONSISTENT", 0, 0, 0, ""),
00617   Commands( "CONSTRAINT", 0, 0, 0, ""),
00618   Commands( "CONTAINS", 0, 0, 0, ""),
00619   Commands( "CONTINUE", 0, 0, 0, ""),
00620   Commands( "CONVERT", 0, 0, 0, ""),
00621   Commands( "CREATE", 0, 0, 0, ""),
00622   Commands( "CROSS", 0, 0, 0, ""),
00623   Commands( "CUBE", 0, 0, 0, ""),
00624   Commands( "CURRENT_DATE", 0, 0, 0, ""),
00625   Commands( "CURRENT_TIMESTAMP", 0, 0, 0, ""),
00626   Commands( "CURRENT_USER", 0, 0, 0, ""),
00627   Commands( "CURSOR", 0, 0, 0, ""),
00628   Commands( "DATA", 0, 0, 0, ""),
00629   Commands( "DATABASE", 0, 0, 0, ""),
00630   Commands( "DATABASES", 0, 0, 0, ""),
00631   Commands( "DATE", 0, 0, 0, ""),
00632   Commands( "DATETIME", 0, 0, 0, ""),
00633   Commands( "DAY", 0, 0, 0, ""),
00634   Commands( "DAY_HOUR", 0, 0, 0, ""),
00635   Commands( "DAY_MICROSECOND", 0, 0, 0, ""),
00636   Commands( "DAY_MINUTE", 0, 0, 0, ""),
00637   Commands( "DAY_SECOND", 0, 0, 0, ""),
00638   Commands( "DEALLOCATE", 0, 0, 0, ""),
00639   Commands( "DEC", 0, 0, 0, ""),
00640   Commands( "DECIMAL", 0, 0, 0, ""),
00641   Commands( "DECLARE", 0, 0, 0, ""),
00642   Commands( "DEFAULT", 0, 0, 0, ""),
00643   Commands( "DEFINER", 0, 0, 0, ""),
00644   Commands( "DELAYED", 0, 0, 0, ""),
00645   Commands( "DELETE", 0, 0, 0, ""),
00646   Commands( "DESC", 0, 0, 0, ""),
00647   Commands( "DESCRIBE", 0, 0, 0, ""),
00648   Commands( "DETERMINISTIC", 0, 0, 0, ""),
00649   Commands( "DISABLE", 0, 0, 0, ""),
00650   Commands( "DISCARD", 0, 0, 0, ""),
00651   Commands( "DISTINCT", 0, 0, 0, ""),
00652   Commands( "DISTINCTROW", 0, 0, 0, ""),
00653   Commands( "DIV", 0, 0, 0, ""),
00654   Commands( "DOUBLE", 0, 0, 0, ""),
00655   Commands( "DROP", 0, 0, 0, ""),
00656   Commands( "DUMPFILE", 0, 0, 0, ""),
00657   Commands( "DUPLICATE", 0, 0, 0, ""),
00658   Commands( "DYNAMIC", 0, 0, 0, ""),
00659   Commands( "EACH", 0, 0, 0, ""),
00660   Commands( "ELSE", 0, 0, 0, ""),
00661   Commands( "ELSEIF", 0, 0, 0, ""),
00662   Commands( "ENABLE", 0, 0, 0, ""),
00663   Commands( "ENCLOSED", 0, 0, 0, ""),
00664   Commands( "END", 0, 0, 0, ""),
00665   Commands( "ENGINE", 0, 0, 0, ""),
00666   Commands( "ENGINES", 0, 0, 0, ""),
00667   Commands( "ENUM", 0, 0, 0, ""),
00668   Commands( "ERRORS", 0, 0, 0, ""),
00669   Commands( "ESCAPE", 0, 0, 0, ""),
00670   Commands( "ESCAPED", 0, 0, 0, ""),
00671   Commands( "EXISTS", 0, 0, 0, ""),
00672   Commands( "EXIT", 0, 0, 0, ""),
00673   Commands( "EXPLAIN", 0, 0, 0, ""),
00674   Commands( "EXTENDED", 0, 0, 0, ""),
00675   Commands( "FALSE", 0, 0, 0, ""),
00676   Commands( "FAST", 0, 0, 0, ""),
00677   Commands( "FETCH", 0, 0, 0, ""),
00678   Commands( "FIELDS", 0, 0, 0, ""),
00679   Commands( "FILE", 0, 0, 0, ""),
00680   Commands( "FIRST", 0, 0, 0, ""),
00681   Commands( "FIXED", 0, 0, 0, ""),
00682   Commands( "FLOAT", 0, 0, 0, ""),
00683   Commands( "FLOAT4", 0, 0, 0, ""),
00684   Commands( "FLOAT8", 0, 0, 0, ""),
00685   Commands( "FLUSH", 0, 0, 0, ""),
00686   Commands( "FOR", 0, 0, 0, ""),
00687   Commands( "FORCE", 0, 0, 0, ""),
00688   Commands( "FOREIGN", 0, 0, 0, ""),
00689   Commands( "FOUND", 0, 0, 0, ""),
00690   Commands( "FRAC_SECOND", 0, 0, 0, ""),
00691   Commands( "FROM", 0, 0, 0, ""),
00692   Commands( "FULL", 0, 0, 0, ""),
00693   Commands( "FUNCTION", 0, 0, 0, ""),
00694   Commands( "GLOBAL", 0, 0, 0, ""),
00695   Commands( "GRANT", 0, 0, 0, ""),
00696   Commands( "GRANTS", 0, 0, 0, ""),
00697   Commands( "GROUP", 0, 0, 0, ""),
00698   Commands( "HANDLER", 0, 0, 0, ""),
00699   Commands( "HASH", 0, 0, 0, ""),
00700   Commands( "HAVING", 0, 0, 0, ""),
00701   Commands( "HELP", 0, 0, 0, ""),
00702   Commands( "HIGH_PRIORITY", 0, 0, 0, ""),
00703   Commands( "HOSTS", 0, 0, 0, ""),
00704   Commands( "HOUR", 0, 0, 0, ""),
00705   Commands( "HOUR_MICROSECOND", 0, 0, 0, ""),
00706   Commands( "HOUR_MINUTE", 0, 0, 0, ""),
00707   Commands( "HOUR_SECOND", 0, 0, 0, ""),
00708   Commands( "IDENTIFIED", 0, 0, 0, ""),
00709   Commands( "IF", 0, 0, 0, ""),
00710   Commands( "IGNORE", 0, 0, 0, ""),
00711   Commands( "IMPORT", 0, 0, 0, ""),
00712   Commands( "IN", 0, 0, 0, ""),
00713   Commands( "INDEX", 0, 0, 0, ""),
00714   Commands( "INDEXES", 0, 0, 0, ""),
00715   Commands( "INFILE", 0, 0, 0, ""),
00716   Commands( "INNER", 0, 0, 0, ""),
00717   Commands( "INNOBASE", 0, 0, 0, ""),
00718   Commands( "INNODB", 0, 0, 0, ""),
00719   Commands( "INOUT", 0, 0, 0, ""),
00720   Commands( "INSENSITIVE", 0, 0, 0, ""),
00721   Commands( "INSERT", 0, 0, 0, ""),
00722   Commands( "INSERT_METHOD", 0, 0, 0, ""),
00723   Commands( "INT", 0, 0, 0, ""),
00724   Commands( "INT1", 0, 0, 0, ""),
00725   Commands( "INT2", 0, 0, 0, ""),
00726   Commands( "INT3", 0, 0, 0, ""),
00727   Commands( "INT4", 0, 0, 0, ""),
00728   Commands( "INT8", 0, 0, 0, ""),
00729   Commands( "INTEGER", 0, 0, 0, ""),
00730   Commands( "INTERVAL", 0, 0, 0, ""),
00731   Commands( "INTO", 0, 0, 0, ""),
00732   Commands( "IO_THREAD", 0, 0, 0, ""),
00733   Commands( "IS", 0, 0, 0, ""),
00734   Commands( "ISOLATION", 0, 0, 0, ""),
00735   Commands( "ISSUER", 0, 0, 0, ""),
00736   Commands( "ITERATE", 0, 0, 0, ""),
00737   Commands( "INVOKER", 0, 0, 0, ""),
00738   Commands( "JOIN", 0, 0, 0, ""),
00739   Commands( "KEY", 0, 0, 0, ""),
00740   Commands( "KEYS", 0, 0, 0, ""),
00741   Commands( "KILL", 0, 0, 0, ""),
00742   Commands( "LANGUAGE", 0, 0, 0, ""),
00743   Commands( "LAST", 0, 0, 0, ""),
00744   Commands( "LEADING", 0, 0, 0, ""),
00745   Commands( "LEAVE", 0, 0, 0, ""),
00746   Commands( "LEAVES", 0, 0, 0, ""),
00747   Commands( "LEFT", 0, 0, 0, ""),
00748   Commands( "LEVEL", 0, 0, 0, ""),
00749   Commands( "LIKE", 0, 0, 0, ""),
00750   Commands( "LIMIT", 0, 0, 0, ""),
00751   Commands( "LINES", 0, 0, 0, ""),
00752   Commands( "LINESTRING", 0, 0, 0, ""),
00753   Commands( "LOAD", 0, 0, 0, ""),
00754   Commands( "LOCAL", 0, 0, 0, ""),
00755   Commands( "LOCALTIMESTAMP", 0, 0, 0, ""),
00756   Commands( "LOCK", 0, 0, 0, ""),
00757   Commands( "LOCKS", 0, 0, 0, ""),
00758   Commands( "LOGS", 0, 0, 0, ""),
00759   Commands( "LONG", 0, 0, 0, ""),
00760   Commands( "LOOP", 0, 0, 0, ""),
00761   Commands( "MATCH", 0, 0, 0, ""),
00762   Commands( "MAX_CONNECTIONS_PER_HOUR", 0, 0, 0, ""),
00763   Commands( "MAX_QUERIES_PER_HOUR", 0, 0, 0, ""),
00764   Commands( "MAX_ROWS", 0, 0, 0, ""),
00765   Commands( "MAX_UPDATES_PER_HOUR", 0, 0, 0, ""),
00766   Commands( "MAX_USER_CONNECTIONS", 0, 0, 0, ""),
00767   Commands( "MEDIUM", 0, 0, 0, ""),
00768   Commands( "MERGE", 0, 0, 0, ""),
00769   Commands( "MICROSECOND", 0, 0, 0, ""),
00770   Commands( "MIGRATE", 0, 0, 0, ""),
00771   Commands( "MINUTE", 0, 0, 0, ""),
00772   Commands( "MINUTE_MICROSECOND", 0, 0, 0, ""),
00773   Commands( "MINUTE_SECOND", 0, 0, 0, ""),
00774   Commands( "MIN_ROWS", 0, 0, 0, ""),
00775   Commands( "MOD", 0, 0, 0, ""),
00776   Commands( "MODE", 0, 0, 0, ""),
00777   Commands( "MODIFIES", 0, 0, 0, ""),
00778   Commands( "MODIFY", 0, 0, 0, ""),
00779   Commands( "MONTH", 0, 0, 0, ""),
00780   Commands( "MULTILINESTRING", 0, 0, 0, ""),
00781   Commands( "MULTIPOINT", 0, 0, 0, ""),
00782   Commands( "MULTIPOLYGON", 0, 0, 0, ""),
00783   Commands( "MUTEX", 0, 0, 0, ""),
00784   Commands( "NAME", 0, 0, 0, ""),
00785   Commands( "NAMES", 0, 0, 0, ""),
00786   Commands( "NATIONAL", 0, 0, 0, ""),
00787   Commands( "NATURAL", 0, 0, 0, ""),
00788   Commands( "NCHAR", 0, 0, 0, ""),
00789   Commands( "NEW", 0, 0, 0, ""),
00790   Commands( "NEXT", 0, 0, 0, ""),
00791   Commands( "NO", 0, 0, 0, ""),
00792   Commands( "NONE", 0, 0, 0, ""),
00793   Commands( "NOT", 0, 0, 0, ""),
00794   Commands( "NULL", 0, 0, 0, ""),
00795   Commands( "NUMERIC", 0, 0, 0, ""),
00796   Commands( "NVARCHAR", 0, 0, 0, ""),
00797   Commands( "OFFSET", 0, 0, 0, ""),
00798   Commands( "ON", 0, 0, 0, ""),
00799   Commands( "ONE", 0, 0, 0, ""),
00800   Commands( "ONE_SHOT", 0, 0, 0, ""),
00801   Commands( "OPEN", 0, 0, 0, ""),
00802   Commands( "OPTIMIZE", 0, 0, 0, ""),
00803   Commands( "OPTION", 0, 0, 0, ""),
00804   Commands( "OPTIONALLY", 0, 0, 0, ""),
00805   Commands( "OR", 0, 0, 0, ""),
00806   Commands( "ORDER", 0, 0, 0, ""),
00807   Commands( "OUT", 0, 0, 0, ""),
00808   Commands( "OUTER", 0, 0, 0, ""),
00809   Commands( "OUTFILE", 0, 0, 0, ""),
00810   Commands( "PACK_KEYS", 0, 0, 0, ""),
00811   Commands( "PARTIAL", 0, 0, 0, ""),
00812   Commands( "PASSWORD", 0, 0, 0, ""),
00813   Commands( "PHASE", 0, 0, 0, ""),
00814   Commands( "PRECISION", 0, 0, 0, ""),
00815   Commands( "PREPARE", 0, 0, 0, ""),
00816   Commands( "PREV", 0, 0, 0, ""),
00817   Commands( "PRIMARY", 0, 0, 0, ""),
00818   Commands( "PRIVILEGES", 0, 0, 0, ""),
00819   Commands( "PROCEDURE", 0, 0, 0, ""),
00820   Commands( "PROCESS", 0, 0, 0, ""),
00821   Commands( "PROCESSLIST", 0, 0, 0, ""),
00822   Commands( "PURGE", 0, 0, 0, ""),
00823   Commands( "QUARTER", 0, 0, 0, ""),
00824   Commands( "QUERY", 0, 0, 0, ""),
00825   Commands( "QUICK", 0, 0, 0, ""),
00826   Commands( "READ", 0, 0, 0, ""),
00827   Commands( "READS", 0, 0, 0, ""),
00828   Commands( "REAL", 0, 0, 0, ""),
00829   Commands( "RECOVER", 0, 0, 0, ""),
00830   Commands( "REDUNDANT", 0, 0, 0, ""),
00831   Commands( "REFERENCES", 0, 0, 0, ""),
00832   Commands( "REGEXP", 0, 0, 0, ""),
00833   Commands( "RELEASE", 0, 0, 0, ""),
00834   Commands( "RELOAD", 0, 0, 0, ""),
00835   Commands( "RENAME", 0, 0, 0, ""),
00836   Commands( "REPAIR", 0, 0, 0, ""),
00837   Commands( "REPEATABLE", 0, 0, 0, ""),
00838   Commands( "REPLACE", 0, 0, 0, ""),
00839   Commands( "REPEAT", 0, 0, 0, ""),
00840   Commands( "REQUIRE", 0, 0, 0, ""),
00841   Commands( "RESET", 0, 0, 0, ""),
00842   Commands( "RESTORE", 0, 0, 0, ""),
00843   Commands( "RESTRICT", 0, 0, 0, ""),
00844   Commands( "RESUME", 0, 0, 0, ""),
00845   Commands( "RETURN", 0, 0, 0, ""),
00846   Commands( "RETURNS", 0, 0, 0, ""),
00847   Commands( "REVOKE", 0, 0, 0, ""),
00848   Commands( "RIGHT", 0, 0, 0, ""),
00849   Commands( "RLIKE", 0, 0, 0, ""),
00850   Commands( "ROLLBACK", 0, 0, 0, ""),
00851   Commands( "ROLLUP", 0, 0, 0, ""),
00852   Commands( "ROUTINE", 0, 0, 0, ""),
00853   Commands( "ROW", 0, 0, 0, ""),
00854   Commands( "ROWS", 0, 0, 0, ""),
00855   Commands( "ROW_FORMAT", 0, 0, 0, ""),
00856   Commands( "RTREE", 0, 0, 0, ""),
00857   Commands( "SAVEPOINT", 0, 0, 0, ""),
00858   Commands( "SCHEMA", 0, 0, 0, ""),
00859   Commands( "SCHEMAS", 0, 0, 0, ""),
00860   Commands( "SECOND", 0, 0, 0, ""),
00861   Commands( "SECOND_MICROSECOND", 0, 0, 0, ""),
00862   Commands( "SECURITY", 0, 0, 0, ""),
00863   Commands( "SELECT", 0, 0, 0, ""),
00864   Commands( "SENSITIVE", 0, 0, 0, ""),
00865   Commands( "SEPARATOR", 0, 0, 0, ""),
00866   Commands( "SERIAL", 0, 0, 0, ""),
00867   Commands( "SERIALIZABLE", 0, 0, 0, ""),
00868   Commands( "SESSION", 0, 0, 0, ""),
00869   Commands( "SET", 0, 0, 0, ""),
00870   Commands( "SHARE", 0, 0, 0, ""),
00871   Commands( "SHOW", 0, 0, 0, ""),
00872   Commands( "SHUTDOWN", 0, 0, 0, ""),
00873   Commands( "SIGNED", 0, 0, 0, ""),
00874   Commands( "SIMPLE", 0, 0, 0, ""),
00875   Commands( "SLAVE", 0, 0, 0, ""),
00876   Commands( "SNAPSHOT", 0, 0, 0, ""),
00877   Commands( "SOME", 0, 0, 0, ""),
00878   Commands( "SONAME", 0, 0, 0, ""),
00879   Commands( "SOUNDS", 0, 0, 0, ""),
00880   Commands( "SPATIAL", 0, 0, 0, ""),
00881   Commands( "SPECIFIC", 0, 0, 0, ""),
00882   Commands( "SQL", 0, 0, 0, ""),
00883   Commands( "SQLEXCEPTION", 0, 0, 0, ""),
00884   Commands( "SQLSTATE", 0, 0, 0, ""),
00885   Commands( "SQLWARNING", 0, 0, 0, ""),
00886   Commands( "SQL_BIG_RESULT", 0, 0, 0, ""),
00887   Commands( "SQL_BUFFER_RESULT", 0, 0, 0, ""),
00888   Commands( "SQL_CACHE", 0, 0, 0, ""),
00889   Commands( "SQL_CALC_FOUND_ROWS", 0, 0, 0, ""),
00890   Commands( "SQL_NO_CACHE", 0, 0, 0, ""),
00891   Commands( "SQL_SMALL_RESULT", 0, 0, 0, ""),
00892   Commands( "SQL_THREAD", 0, 0, 0, ""),
00893   Commands( "SQL_TSI_FRAC_SECOND", 0, 0, 0, ""),
00894   Commands( "SQL_TSI_SECOND", 0, 0, 0, ""),
00895   Commands( "SQL_TSI_MINUTE", 0, 0, 0, ""),
00896   Commands( "SQL_TSI_HOUR", 0, 0, 0, ""),
00897   Commands( "SQL_TSI_DAY", 0, 0, 0, ""),
00898   Commands( "SQL_TSI_WEEK", 0, 0, 0, ""),
00899   Commands( "SQL_TSI_MONTH", 0, 0, 0, ""),
00900   Commands( "SQL_TSI_QUARTER", 0, 0, 0, ""),
00901   Commands( "SQL_TSI_YEAR", 0, 0, 0, ""),
00902   Commands( "SSL", 0, 0, 0, ""),
00903   Commands( "START", 0, 0, 0, ""),
00904   Commands( "STARTING", 0, 0, 0, ""),
00905   Commands( "STATUS", 0, 0, 0, ""),
00906   Commands( "STOP", 0, 0, 0, ""),
00907   Commands( "STORAGE", 0, 0, 0, ""),
00908   Commands( "STRAIGHT_JOIN", 0, 0, 0, ""),
00909   Commands( "STRING", 0, 0, 0, ""),
00910   Commands( "STRIPED", 0, 0, 0, ""),
00911   Commands( "SUBJECT", 0, 0, 0, ""),
00912   Commands( "SUPER", 0, 0, 0, ""),
00913   Commands( "SUSPEND", 0, 0, 0, ""),
00914   Commands( "TABLE", 0, 0, 0, ""),
00915   Commands( "TABLES", 0, 0, 0, ""),
00916   Commands( "TABLESPACE", 0, 0, 0, ""),
00917   Commands( "TEMPORARY", 0, 0, 0, ""),
00918   Commands( "TEMPTABLE", 0, 0, 0, ""),
00919   Commands( "TERMINATED", 0, 0, 0, ""),
00920   Commands( "TEXT", 0, 0, 0, ""),
00921   Commands( "THEN", 0, 0, 0, ""),
00922   Commands( "TIMESTAMP", 0, 0, 0, ""),
00923   Commands( "TIMESTAMPADD", 0, 0, 0, ""),
00924   Commands( "TIMESTAMPDIFF", 0, 0, 0, ""),
00925   Commands( "TO", 0, 0, 0, ""),
00926   Commands( "TRAILING", 0, 0, 0, ""),
00927   Commands( "TRANSACTION", 0, 0, 0, ""),
00928   Commands( "TRUE", 0, 0, 0, ""),
00929   Commands( "TRUNCATE", 0, 0, 0, ""),
00930   Commands( "TYPE", 0, 0, 0, ""),
00931   Commands( "TYPES", 0, 0, 0, ""),
00932   Commands( "UNCOMMITTED", 0, 0, 0, ""),
00933   Commands( "UNDEFINED", 0, 0, 0, ""),
00934   Commands( "UNDO", 0, 0, 0, ""),
00935   Commands( "UNICODE", 0, 0, 0, ""),
00936   Commands( "UNION", 0, 0, 0, ""),
00937   Commands( "UNIQUE", 0, 0, 0, ""),
00938   Commands( "UNKNOWN", 0, 0, 0, ""),
00939   Commands( "UNLOCK", 0, 0, 0, ""),
00940   Commands( "UNTIL", 0, 0, 0, ""),
00941   Commands( "UPDATE", 0, 0, 0, ""),
00942   Commands( "UPGRADE", 0, 0, 0, ""),
00943   Commands( "USAGE", 0, 0, 0, ""),
00944   Commands( "USE", 0, 0, 0, ""),
00945   Commands( "USER", 0, 0, 0, ""),
00946   Commands( "USER_RESOURCES", 0, 0, 0, ""),
00947   Commands( "USING", 0, 0, 0, ""),
00948   Commands( "UTC_DATE", 0, 0, 0, ""),
00949   Commands( "UTC_TIMESTAMP", 0, 0, 0, ""),
00950   Commands( "VALUE", 0, 0, 0, ""),
00951   Commands( "VALUES", 0, 0, 0, ""),
00952   Commands( "VARBINARY", 0, 0, 0, ""),
00953   Commands( "VARCHAR", 0, 0, 0, ""),
00954   Commands( "VARCHARACTER", 0, 0, 0, ""),
00955   Commands( "VARIABLES", 0, 0, 0, ""),
00956   Commands( "VARYING", 0, 0, 0, ""),
00957   Commands( "WARNINGS", 0, 0, 0, ""),
00958   Commands( "WEEK", 0, 0, 0, ""),
00959   Commands( "WHEN", 0, 0, 0, ""),
00960   Commands( "WHERE", 0, 0, 0, ""),
00961   Commands( "WHILE", 0, 0, 0, ""),
00962   Commands( "VIEW", 0, 0, 0, ""),
00963   Commands( "WITH", 0, 0, 0, ""),
00964   Commands( "WORK", 0, 0, 0, ""),
00965   Commands( "WRITE", 0, 0, 0, ""),
00966   Commands( "XOR", 0, 0, 0, ""),
00967   Commands( "XA", 0, 0, 0, ""),
00968   Commands( "YEAR", 0, 0, 0, ""),
00969   Commands( "YEAR_MONTH", 0, 0, 0, ""),
00970   Commands( "ZEROFILL", 0, 0, 0, ""),
00971   Commands( "ABS", 0, 0, 0, ""),
00972   Commands( "ACOS", 0, 0, 0, ""),
00973   Commands( "ADDDATE", 0, 0, 0, ""),
00974   Commands( "AREA", 0, 0, 0, ""),
00975   Commands( "ASIN", 0, 0, 0, ""),
00976   Commands( "ASBINARY", 0, 0, 0, ""),
00977   Commands( "ASTEXT", 0, 0, 0, ""),
00978   Commands( "ATAN", 0, 0, 0, ""),
00979   Commands( "ATAN2", 0, 0, 0, ""),
00980   Commands( "BENCHMARK", 0, 0, 0, ""),
00981   Commands( "BIN", 0, 0, 0, ""),
00982   Commands( "BIT_OR", 0, 0, 0, ""),
00983   Commands( "BIT_AND", 0, 0, 0, ""),
00984   Commands( "BIT_XOR", 0, 0, 0, ""),
00985   Commands( "CAST", 0, 0, 0, ""),
00986   Commands( "CEIL", 0, 0, 0, ""),
00987   Commands( "CEILING", 0, 0, 0, ""),
00988   Commands( "CENTROID", 0, 0, 0, ""),
00989   Commands( "CHAR_LENGTH", 0, 0, 0, ""),
00990   Commands( "CHARACTER_LENGTH", 0, 0, 0, ""),
00991   Commands( "COALESCE", 0, 0, 0, ""),
00992   Commands( "COERCIBILITY", 0, 0, 0, ""),
00993   Commands( "COMPRESS", 0, 0, 0, ""),
00994   Commands( "CONCAT", 0, 0, 0, ""),
00995   Commands( "CONCAT_WS", 0, 0, 0, ""),
00996   Commands( "CONNECTION_ID", 0, 0, 0, ""),
00997   Commands( "CONV", 0, 0, 0, ""),
00998   Commands( "CONVERT_TZ", 0, 0, 0, ""),
00999   Commands( "COUNT", 0, 0, 0, ""),
01000   Commands( "COS", 0, 0, 0, ""),
01001   Commands( "COT", 0, 0, 0, ""),
01002   Commands( "CRC32", 0, 0, 0, ""),
01003   Commands( "CROSSES", 0, 0, 0, ""),
01004   Commands( "CURDATE", 0, 0, 0, ""),
01005   Commands( "DATE_ADD", 0, 0, 0, ""),
01006   Commands( "DATEDIFF", 0, 0, 0, ""),
01007   Commands( "DATE_FORMAT", 0, 0, 0, ""),
01008   Commands( "DATE_SUB", 0, 0, 0, ""),
01009   Commands( "DAYNAME", 0, 0, 0, ""),
01010   Commands( "DAYOFMONTH", 0, 0, 0, ""),
01011   Commands( "DAYOFWEEK", 0, 0, 0, ""),
01012   Commands( "DAYOFYEAR", 0, 0, 0, ""),
01013   Commands( "DECODE", 0, 0, 0, ""),
01014   Commands( "DEGREES", 0, 0, 0, ""),
01015   Commands( "DES_ENCRYPT", 0, 0, 0, ""),
01016   Commands( "DES_DECRYPT", 0, 0, 0, ""),
01017   Commands( "DIMENSION", 0, 0, 0, ""),
01018   Commands( "DISJOINT", 0, 0, 0, ""),
01019   Commands( "ELT", 0, 0, 0, ""),
01020   Commands( "ENCODE", 0, 0, 0, ""),
01021   Commands( "ENCRYPT", 0, 0, 0, ""),
01022   Commands( "ENDPOINT", 0, 0, 0, ""),
01023   Commands( "ENVELOPE", 0, 0, 0, ""),
01024   Commands( "EQUALS", 0, 0, 0, ""),
01025   Commands( "EXTERIORRING", 0, 0, 0, ""),
01026   Commands( "EXTRACT", 0, 0, 0, ""),
01027   Commands( "EXP", 0, 0, 0, ""),
01028   Commands( "EXPORT_SET", 0, 0, 0, ""),
01029   Commands( "FIELD", 0, 0, 0, ""),
01030   Commands( "FIND_IN_SET", 0, 0, 0, ""),
01031   Commands( "FLOOR", 0, 0, 0, ""),
01032   Commands( "FORMAT", 0, 0, 0, ""),
01033   Commands( "FOUND_ROWS", 0, 0, 0, ""),
01034   Commands( "FROM_DAYS", 0, 0, 0, ""),
01035   Commands( "FROM_UNIXTIME", 0, 0, 0, ""),
01036   Commands( "GET_LOCK", 0, 0, 0, ""),
01037   Commands( "GLENGTH", 0, 0, 0, ""),
01038   Commands( "GREATEST", 0, 0, 0, ""),
01039   Commands( "GROUP_CONCAT", 0, 0, 0, ""),
01040   Commands( "GROUP_UNIQUE_USERS", 0, 0, 0, ""),
01041   Commands( "HEX", 0, 0, 0, ""),
01042   Commands( "IFNULL", 0, 0, 0, ""),
01043   Commands( "INSTR", 0, 0, 0, ""),
01044   Commands( "INTERIORRINGN", 0, 0, 0, ""),
01045   Commands( "INTERSECTS", 0, 0, 0, ""),
01046   Commands( "ISCLOSED", 0, 0, 0, ""),
01047   Commands( "ISEMPTY", 0, 0, 0, ""),
01048   Commands( "ISNULL", 0, 0, 0, ""),
01049   Commands( "IS_FREE_LOCK", 0, 0, 0, ""),
01050   Commands( "IS_USED_LOCK", 0, 0, 0, ""),
01051   Commands( "LAST_INSERT_ID", 0, 0, 0, ""),
01052   Commands( "ISSIMPLE", 0, 0, 0, ""),
01053   Commands( "LAST_DAY", 0, 0, 0, ""),
01054   Commands( "LCASE", 0, 0, 0, ""),
01055   Commands( "LEAST", 0, 0, 0, ""),
01056   Commands( "LENGTH", 0, 0, 0, ""),
01057   Commands( "LN", 0, 0, 0, ""),
01058   Commands( "LOAD_FILE", 0, 0, 0, ""),
01059   Commands( "LOCATE", 0, 0, 0, ""),
01060   Commands( "LOG", 0, 0, 0, ""),
01061   Commands( "LOG2", 0, 0, 0, ""),
01062   Commands( "LOG10", 0, 0, 0, ""),
01063   Commands( "LOWER", 0, 0, 0, ""),
01064   Commands( "LPAD", 0, 0, 0, ""),
01065   Commands( "LTRIM", 0, 0, 0, ""),
01066   Commands( "MAKE_SET", 0, 0, 0, ""),
01067   Commands( "MAKEDATE", 0, 0, 0, ""),
01068   Commands( "MASTER_POS_WAIT", 0, 0, 0, ""),
01069   Commands( "MAX", 0, 0, 0, ""),
01070   Commands( "MBRCONTAINS", 0, 0, 0, ""),
01071   Commands( "MBRDISJOINT", 0, 0, 0, ""),
01072   Commands( "MBREQUAL", 0, 0, 0, ""),
01073   Commands( "MBRINTERSECTS", 0, 0, 0, ""),
01074   Commands( "MBROVERLAPS", 0, 0, 0, ""),
01075   Commands( "MBRTOUCHES", 0, 0, 0, ""),
01076   Commands( "MBRWITHIN", 0, 0, 0, ""),
01077   Commands( "MD5", 0, 0, 0, ""),
01078   Commands( "MID", 0, 0, 0, ""),
01079   Commands( "MIN", 0, 0, 0, ""),
01080   Commands( "MONTHNAME", 0, 0, 0, ""),
01081   Commands( "NAME_CONST", 0, 0, 0, ""),
01082   Commands( "NOW", 0, 0, 0, ""),
01083   Commands( "NULLIF", 0, 0, 0, ""),
01084   Commands( "NUMPOINTS", 0, 0, 0, ""),
01085   Commands( "OCTET_LENGTH", 0, 0, 0, ""),
01086   Commands( "OCT", 0, 0, 0, ""),
01087   Commands( "ORD", 0, 0, 0, ""),
01088   Commands( "OVERLAPS", 0, 0, 0, ""),
01089   Commands( "PERIOD_ADD", 0, 0, 0, ""),
01090   Commands( "PERIOD_DIFF", 0, 0, 0, ""),
01091   Commands( "PI", 0, 0, 0, ""),
01092   Commands( "POINTN", 0, 0, 0, ""),
01093   Commands( "POSITION", 0, 0, 0, ""),
01094   Commands( "POW", 0, 0, 0, ""),
01095   Commands( "POWER", 0, 0, 0, ""),
01096   Commands( "QUOTE", 0, 0, 0, ""),
01097   Commands( "RADIANS", 0, 0, 0, ""),
01098   Commands( "RAND", 0, 0, 0, ""),
01099   Commands( "RELEASE_LOCK", 0, 0, 0, ""),
01100   Commands( "REVERSE", 0, 0, 0, ""),
01101   Commands( "ROUND", 0, 0, 0, ""),
01102   Commands( "ROW_COUNT", 0, 0, 0, ""),
01103   Commands( "RPAD", 0, 0, 0, ""),
01104   Commands( "RTRIM", 0, 0, 0, ""),
01105   Commands( "SESSION_USER", 0, 0, 0, ""),
01106   Commands( "SUBDATE", 0, 0, 0, ""),
01107   Commands( "SIGN", 0, 0, 0, ""),
01108   Commands( "SIN", 0, 0, 0, ""),
01109   Commands( "SHA", 0, 0, 0, ""),
01110   Commands( "SHA1", 0, 0, 0, ""),
01111   Commands( "SLEEP", 0, 0, 0, ""),
01112   Commands( "SOUNDEX", 0, 0, 0, ""),
01113   Commands( "SPACE", 0, 0, 0, ""),
01114   Commands( "SQRT", 0, 0, 0, ""),
01115   Commands( "SRID", 0, 0, 0, ""),
01116   Commands( "STARTPOINT", 0, 0, 0, ""),
01117   Commands( "STD", 0, 0, 0, ""),
01118   Commands( "STDDEV", 0, 0, 0, ""),
01119   Commands( "STDDEV_POP", 0, 0, 0, ""),
01120   Commands( "STDDEV_SAMP", 0, 0, 0, ""),
01121   Commands( "STR_TO_DATE", 0, 0, 0, ""),
01122   Commands( "STRCMP", 0, 0, 0, ""),
01123   Commands( "SUBSTR", 0, 0, 0, ""),
01124   Commands( "SUBSTRING", 0, 0, 0, ""),
01125   Commands( "SUBSTRING_INDEX", 0, 0, 0, ""),
01126   Commands( "SUM", 0, 0, 0, ""),
01127   Commands( "SYSDATE", 0, 0, 0, ""),
01128   Commands( "SYSTEM_USER", 0, 0, 0, ""),
01129   Commands( "TAN", 0, 0, 0, ""),
01130   Commands( "TIME_FORMAT", 0, 0, 0, ""),
01131   Commands( "TO_DAYS", 0, 0, 0, ""),
01132   Commands( "TOUCHES", 0, 0, 0, ""),
01133   Commands( "TRIM", 0, 0, 0, ""),
01134   Commands( "UCASE", 0, 0, 0, ""),
01135   Commands( "UNCOMPRESS", 0, 0, 0, ""),
01136   Commands( "UNCOMPRESSED_LENGTH", 0, 0, 0, ""),
01137   Commands( "UNHEX", 0, 0, 0, ""),
01138   Commands( "UNIQUE_USERS", 0, 0, 0, ""),
01139   Commands( "UNIX_TIMESTAMP", 0, 0, 0, ""),
01140   Commands( "UPPER", 0, 0, 0, ""),
01141   Commands( "UUID", 0, 0, 0, ""),
01142   Commands( "VARIANCE", 0, 0, 0, ""),
01143   Commands( "VAR_POP", 0, 0, 0, ""),
01144   Commands( "VAR_SAMP", 0, 0, 0, ""),
01145   Commands( "VERSION", 0, 0, 0, ""),
01146   Commands( "WEEKDAY", 0, 0, 0, ""),
01147   Commands( "WEEKOFYEAR", 0, 0, 0, ""),
01148   Commands( "WITHIN", 0, 0, 0, ""),
01149   Commands( "X", 0, 0, 0, ""),
01150   Commands( "Y", 0, 0, 0, ""),
01151   Commands( "YEARWEEK", 0, 0, 0, ""),
01152   /* end sentinel */
01153   Commands((char *)NULL,       0, 0, 0, "")
01154 };
01155 
01156 
01157 int history_length;
01158 static int not_in_history(const char *line);
01159 static void initialize_readline (char *name);
01160 static void fix_history(string *final_command);
01161 
01162 static Commands *find_command(const char *name,char cmd_name);
01163 static bool add_line(string *buffer,char *line,char *in_string,
01164                      bool *ml_comment);
01165 static void remove_cntrl(string *buffer);
01166 static void print_table_data(drizzle_result_st *result);
01167 static void print_tab_data(drizzle_result_st *result);
01168 static void print_table_data_vertically(drizzle_result_st *result);
01169 static void print_warnings(uint32_t error_code);
01170 static boost::posix_time::ptime start_timer(void);
01171 static void end_timer(boost::posix_time::ptime, string &buff);
01172 static void drizzle_end_timer(boost::posix_time::ptime, string &buff);
01173 static void nice_time(boost::posix_time::time_duration duration, string &buff);
01174 extern "C" void drizzle_end(int sig);
01175 extern "C" void handle_sigint(int sig);
01176 #if defined(HAVE_TERMIOS_H) && defined(GWINSZ_IN_SYS_IOCTL)
01177 static void window_resize(int sig);
01178 #endif
01179 
01188 static bool server_shutdown(void)
01189 {
01190   drizzle_result_st result;
01191 
01192   if (verbose)
01193   {
01194     printf(_("shutting down drizzled"));
01195     if (opt_drizzle_port > 0)
01196     {
01197       printf(_(" on port %d"), opt_drizzle_port);
01198     }
01199     printf("... ");
01200   }
01201 
01202   drizzle_return_t ret;
01203   if (drizzle_shutdown(con, &result, DRIZZLE_SHUTDOWN_DEFAULT, &ret) == NULL or
01204       ret != DRIZZLE_RETURN_OK)
01205   {
01206     if (ret == DRIZZLE_RETURN_ERROR_CODE)
01207     {
01208       fprintf(stderr, _("shutdown failed; error: '%s'"), drizzle_result_error(&result));
01209       drizzle_result_free(&result);
01210     }
01211     else
01212     {
01213       fprintf(stderr, _("shutdown failed; error: '%s'"), drizzle_con_error(con));
01214     }
01215     return false;
01216   }
01217 
01218   drizzle_result_free(&result);
01219 
01220   if (verbose)
01221   {
01222     printf(_("done\n"));
01223   }
01224 
01225   return true;
01226 }
01227 
01228 static bool kill_query(uint32_t query_id)
01229 {
01230   drizzle_result_st result;
01231   drizzle_return_t ret;
01232 
01233   if (verbose)
01234   {
01235     printf(_("killing query %u"), query_id);
01236     printf("... ");
01237   }
01238 
01239   if (drizzle_kill(con, &result, query_id,
01240                    &ret) == NULL || ret != DRIZZLE_RETURN_OK)
01241   {
01242     if (ret == DRIZZLE_RETURN_ERROR_CODE)
01243     {
01244       fprintf(stderr, _("kill failed; error: '%s'"),
01245               drizzle_result_error(&result));
01246       drizzle_result_free(&result);
01247     }
01248     else
01249     {
01250       fprintf(stderr, _("kill failed; error: '%s'"), drizzle_con_error(con));
01251     }
01252     return false;
01253   }
01254 
01255   drizzle_result_free(&result);
01256 
01257   if (verbose)
01258     printf(_("done\n"));
01259 
01260   return true;
01261 }
01262 
01271 static bool server_ping(void)
01272 {
01273   drizzle_result_st result;
01274   drizzle_return_t ret;
01275 
01276   if (drizzle_ping(con, &result, &ret) != NULL && ret == DRIZZLE_RETURN_OK)
01277   {
01278     if (opt_silent < 2)
01279       printf(_("drizzled is alive\n"));
01280   }
01281   else
01282   {
01283     if (ret == DRIZZLE_RETURN_ERROR_CODE)
01284     {
01285       fprintf(stderr, _("ping failed; error: '%s'"),
01286               drizzle_result_error(&result));
01287       drizzle_result_free(&result);
01288     }
01289     else
01290     {
01291       fprintf(stderr, _("drizzled won't answer to ping, error: '%s'"), drizzle_con_error(con));
01292     }
01293     return false;
01294   }
01295   drizzle_result_free(&result);
01296   return true;
01297 }
01298 
01313 static bool execute_commands(int *error)
01314 {
01315   bool executed= false;
01316   *error= 0;
01317 
01318   if (opt_ping)
01319   {
01320     if (server_ping() == false)
01321       *error= 1;
01322     executed= true;
01323   }
01324 
01325   if (opt_shutdown)
01326   {
01327     if (server_shutdown() == false)
01328       *error= 1;
01329     executed= true;
01330   }
01331 
01332   if (opt_kill)
01333   {
01334     if (kill_query(opt_kill) == false)
01335     {
01336       *error= 1;
01337     }
01338     executed= true;
01339   }
01340 
01341   return executed;
01342 }
01343 
01344 static void check_timeout_value(uint32_t in_connect_timeout)
01345 {
01346   opt_connect_timeout= 0;
01347   if (in_connect_timeout > 3600*12)
01348   {
01349     cout << _("Error: Invalid Value for connect_timeout"); 
01350     exit(-1);
01351   }
01352   opt_connect_timeout= in_connect_timeout;
01353 }
01354 
01355 static void check_max_input_line(uint32_t in_max_input_line)
01356 {
01357   opt_max_input_line= 0;
01358   if (in_max_input_line < 4096 || in_max_input_line > (int64_t)2*1024L*1024L*1024L)
01359   {
01360     cout << _("Error: Invalid Value for max_input_line");
01361     exit(-1);
01362   }
01363   opt_max_input_line= in_max_input_line - (in_max_input_line % 1024);
01364 }
01365 
01366 int main(int argc,char *argv[])
01367 {
01368 try
01369 {
01370 
01371 #if defined(ENABLE_NLS)
01372 # if defined(HAVE_LOCALE_H)
01373   setlocale(LC_ALL, "");
01374 # endif
01375   bindtextdomain("drizzle7", LOCALEDIR);
01376   textdomain("drizzle7");
01377 #endif
01378 
01379   po::options_description commandline_options(_("Options used only in command line"));
01380   commandline_options.add_options()
01381   ("help,?",_("Displays this help and exit."))
01382   ("batch,B",_("Don't use history file. Disable interactive behavior. (Enables --silent)"))
01383   ("column-type-info", po::value<bool>(&column_types_flag)->default_value(false)->zero_tokens(),
01384   _("Display column type information."))
01385   ("comments,c", po::value<bool>(&preserve_comments)->default_value(false)->zero_tokens(),
01386   _("Preserve comments. Send comments to the server. The default is --skip-comments (discard comments), enable with --comments"))
01387   ("vertical,E", po::value<bool>(&vertical)->default_value(false)->zero_tokens(),
01388   _("Print the output of a query (rows) vertically."))
01389   ("force,f", po::value<bool>(&ignore_errors)->default_value(false)->zero_tokens(),
01390   _("Continue even if we get an sql error."))
01391   ("named-commands,G", po::value<bool>(&named_cmds)->default_value(false)->zero_tokens(),
01392   _("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."))
01393   ("no-beep,b", po::value<bool>(&opt_nobeep)->default_value(false)->zero_tokens(),
01394   _("Turn off beep on error."))
01395   ("disable-line-numbers", _("Do not write line numbers for errors."))
01396   ("disable-column-names", _("Do not write column names in results."))
01397   ("skip-column-names,N", 
01398   _("Don't write column names in results. WARNING: -N is deprecated, use long version of this options instead."))
01399   ("set-variable,O", po::value<string>(),
01400   _("Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value."))
01401   ("table,t", po::value<bool>(&output_tables)->default_value(false)->zero_tokens(),
01402   _("Output in table format.")) 
01403   ("safe-updates,U", po::value<bool>(&safe_updates)->default_value(false)->zero_tokens(),
01404   _("Only allow UPDATE and DELETE that uses keys."))
01405   ("i-am-a-dummy,U", po::value<bool>(&safe_updates)->default_value(false)->zero_tokens(),
01406   _("Synonym for option --safe-updates, -U."))
01407   ("verbose,v", po::value<string>(&opt_verbose)->default_value(""),
01408   _("-v vvv implies that verbose= 3, Used to specify verbose"))
01409   ("version,V", _("Output version information and exit."))
01410   ("secure-auth", po::value<bool>(&opt_secure_auth)->default_value(false)->zero_tokens(),
01411   _("Refuse client connecting to server if it uses old (pre-4.1.1) protocol"))
01412   ("show-warnings", po::value<bool>(&show_warnings)->default_value(false)->zero_tokens(),
01413   _("Show warnings after every statement."))
01414   ("show-progress-size", po::value<uint32_t>(&show_progress_size)->default_value(0),
01415   _("Number of lines before each import progress report."))
01416   ("ping", po::value<bool>(&opt_ping)->default_value(false)->zero_tokens(),
01417   _("Ping the server to check if it's alive."))
01418   ("no-defaults", po::value<bool>()->default_value(false)->zero_tokens(),
01419   _("Configuration file defaults are not used if no-defaults is set"))
01420   ;
01421 
01422   po::options_description drizzle_options(_("Options specific to the drizzle client"));
01423   drizzle_options.add_options()
01424   ("disable-auto-rehash,A",
01425   _("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."))
01426   ("auto-vertical-output", po::value<bool>(&auto_vertical_output)->default_value(false)->zero_tokens(),
01427   _("Automatically switch to vertical output mode if the result is wider than the terminal width."))
01428   ("database,D", po::value<string>(&current_db)->default_value(""),
01429   _("Database to use."))
01430   ("default-character-set",po::value<string>(),
01431   _("(not used)"))
01432   ("delimiter", po::value<string>(&delimiter_str)->default_value(";"),
01433   _("Delimiter to be used."))
01434   ("execute,e", po::value<string>(),
01435   _("Execute command and quit. (Disables --force and history file)"))
01436   ("local-infile", po::value<bool>(&opt_local_infile)->default_value(false)->zero_tokens(),
01437   _("Enable LOAD DATA LOCAL INFILE."))
01438   ("unbuffered,n", po::value<bool>(&unbuffered)->default_value(false)->zero_tokens(),
01439   _("Flush buffer after each query."))
01440   ("sigint-ignore", po::value<bool>(&opt_sigint_ignore)->default_value(false)->zero_tokens(),
01441   _("Ignore SIGINT (CTRL-C)"))
01442   ("one-database,o", po::value<bool>(&one_database)->default_value(false)->zero_tokens(),
01443   _("Only update the default database. This is useful for skipping updates to other database in the update log."))
01444   ("pager", po::value<string>(),
01445   _("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."))
01446   ("disable-pager", po::value<bool>(&opt_nopager)->default_value(false)->zero_tokens(),
01447   _("Disable pager and print to stdout. See interactive help (\\h) also."))
01448   ("prompt", po::value<string>(&current_prompt)->default_value(""),  
01449   _("Set the drizzle prompt to this value."))
01450   ("quick,q", po::value<bool>(&quick)->default_value(false)->zero_tokens(),
01451   _("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."))
01452   ("raw,r", po::value<bool>(&opt_raw_data)->default_value(false)->zero_tokens(),
01453   _("Write fields without conversion. Used with --batch.")) 
01454   ("disable-reconnect", _("Do not reconnect if the connection is lost."))
01455   ("shutdown", po::value<bool>()->zero_tokens(),
01456   _("Shutdown the server"))
01457   ("silent,s", _("Be more silent. Print results with a tab as separator, each row on new line."))
01458   ("kill", po::value<uint32_t>(&opt_kill)->default_value(0),
01459   _("Kill a running query."))
01460   ("tee", po::value<string>(),
01461   _("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."))
01462   ("disable-tee", po::value<bool>()->default_value(false)->zero_tokens(), 
01463   _("Disable outfile. See interactive help (\\h) also."))
01464   ("connect-timeout", po::value<uint32_t>(&opt_connect_timeout)->default_value(0)->notifier(&check_timeout_value),
01465   _("Number of seconds before connection timeout."))
01466   ("max-input-line", po::value<uint32_t>(&opt_max_input_line)->default_value(16*1024L*1024L)->notifier(&check_max_input_line),
01467   _("Max length of input line"))
01468   ("select-limit", po::value<uint32_t>(&select_limit)->default_value(1000L),
01469   _("Automatic limit for SELECT when using --safe-updates"))
01470   ("max-join-size", po::value<uint32_t>(&max_join_size)->default_value(1000000L),
01471   _("Automatic limit for rows in a join when using --safe-updates"))
01472   ;
01473 
01474   po::options_description client_options(_("Options specific to the client"));
01475   client_options.add_options()
01476   ("host,h", po::value<string>(&current_host)->default_value("localhost"),
01477   _("Connect to host"))
01478   ("password,P", po::value<string>(&current_password)->default_value(PASSWORD_SENTINEL),
01479   _("Password to use when connecting to server. If password is not given it's asked from the tty."))
01480   ("port,p", po::value<uint32_t>()->default_value(0),
01481   _("Port number to use for connection or 0 for default to, in order of preference, drizzle.cnf, $DRIZZLE_TCP_PORT, built-in default"))
01482   ("user,u", po::value<string>(&current_user)->default_value(UserDetect().getUser()),
01483   _("User for login if not current user."))
01484   ("protocol",po::value<string>(&opt_protocol)->default_value("mysql"),
01485   _("The protocol of connection (mysql, mysql-plugin-auth, or drizzle)."))
01486   ;
01487   po::options_description long_options(_("Allowed Options"));
01488   long_options.add(commandline_options).add(drizzle_options).add(client_options);
01489 
01490   std::string system_config_dir_drizzle(SYSCONFDIR); 
01491   system_config_dir_drizzle.append("/drizzle/drizzle.cnf");
01492 
01493   std::string system_config_dir_client(SYSCONFDIR); 
01494   system_config_dir_client.append("/drizzle/client.cnf");
01495 
01496   std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
01497  
01498   if (user_config_dir.compare(0, 2, "~/") == 0)
01499   {
01500     char *homedir;
01501     homedir= getenv("HOME");
01502     if (homedir != NULL)
01503       user_config_dir.replace(0, 1, homedir);
01504   }
01505  
01506   po::variables_map vm;
01507 
01508   po::positional_options_description p;
01509   p.add("database", 1);
01510 
01511   // Disable allow_guessing
01512   int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
01513 
01514   po::store(po::command_line_parser(argc, argv).options(long_options).
01515             style(style).positional(p).extra_parser(parse_password_arg).run(),
01516             vm);
01517 
01518   if (! vm["no-defaults"].as<bool>())
01519   {
01520     std::string user_config_dir_drizzle(user_config_dir);
01521     user_config_dir_drizzle.append("/drizzle/drizzle.cnf"); 
01522 
01523     std::string user_config_dir_client(user_config_dir);
01524     user_config_dir_client.append("/drizzle/client.cnf");
01525 
01526     ifstream user_drizzle_ifs(user_config_dir_drizzle.c_str());
01527     po::store(dpo::parse_config_file(user_drizzle_ifs, drizzle_options), vm);
01528 
01529     ifstream user_client_ifs(user_config_dir_client.c_str());
01530     po::store(dpo::parse_config_file(user_client_ifs, client_options), vm);
01531 
01532     ifstream system_drizzle_ifs(system_config_dir_drizzle.c_str());
01533     store(dpo::parse_config_file(system_drizzle_ifs, drizzle_options), vm);
01534  
01535     ifstream system_client_ifs(system_config_dir_client.c_str());
01536     po::store(dpo::parse_config_file(system_client_ifs, client_options), vm);
01537   }
01538 
01539   po::notify(vm);
01540 
01541   default_prompt= strdup(getenv("DRIZZLE_PS1") ?
01542                          getenv("DRIZZLE_PS1") :
01543                          "drizzle> ");
01544   if (default_prompt == NULL)
01545   {
01546     fprintf(stderr, _("Memory allocation error while constructing initial "
01547                       "prompt. Aborting.\n"));
01548     exit(ENOMEM);
01549   }
01550 
01551   if (current_prompt.empty())
01552     current_prompt= strdup(default_prompt);
01553 
01554   if (current_prompt.empty())
01555   {
01556     fprintf(stderr, _("Memory allocation error while constructing initial "
01557                       "prompt. Aborting.\n"));
01558     exit(ENOMEM);
01559   }
01560   processed_prompt= new string();
01561   processed_prompt->reserve(32);
01562 
01563   prompt_counter=0;
01564 
01565   outfile.clear();      // no (default) outfile
01566   pager= "stdout";  // the default, if --pager wasn't given
01567   if (const char* tmp= getenv("PAGER"))
01568   {
01569     if (*tmp)
01570     {
01571       default_pager_set= 1;
01572       default_pager= tmp;
01573     }
01574   }
01575   if (not isatty(0) || not isatty(1))
01576   {
01577     status.setBatch(1); 
01578     opt_silent= 1;
01579   }
01580   else
01581     status.setAddToHistory(1);
01582   status.setExitStatus(1);
01583 
01584   {
01585     /*
01586       The file descriptor-layer may be out-of-sync with the file-number layer,
01587       so we make sure that "stdout" is really open.  If its file is closed then
01588       explicitly close the FD layer.
01589     */
01590     int stdout_fileno_copy;
01591     stdout_fileno_copy= dup(fileno(stdout)); /* Okay if fileno fails. */
01592     if (stdout_fileno_copy == -1)
01593       fclose(stdout);
01594     else
01595       close(stdout_fileno_copy);             /* Clean up dup(). */
01596   }
01597 
01598   /* Inverted Booleans */
01599 
01600   line_numbers= not vm.count("disable-line-numbers");
01601   column_names= not vm.count("disable-column-names");
01602   opt_rehash= not vm.count("disable-auto-rehash");
01603   opt_reconnect= not vm.count("disable-reconnect");
01604 
01605   /* Don't rehash with --shutdown */
01606   if (vm.count("shutdown"))
01607   {
01608     opt_rehash= false;
01609     opt_shutdown= true;
01610   }
01611 
01612   if (vm.count("delimiter"))
01613   {
01614     /* Check that delimiter does not contain a backslash */
01615     if (! strstr(delimiter_str.c_str(), "\\"))
01616     {
01617       delimiter= delimiter_str.c_str();  
01618     }
01619     else
01620     {
01621       put_info(_("DELIMITER cannot contain a backslash character"),
01622       INFO_ERROR,0,0);
01623       exit(-1);
01624     }
01625    
01626     delimiter_length= (uint32_t)strlen(delimiter);
01627   }
01628   if (vm.count("tee"))
01629   { 
01630     if (vm["tee"].as<string>().empty())
01631     {
01632       if (opt_outfile)
01633         end_tee();
01634     }
01635     else
01636       init_tee(vm["tee"].as<string>().c_str());
01637   }
01638   if (vm["disable-tee"].as<bool>())
01639   {
01640     if (opt_outfile)
01641       end_tee();
01642   }
01643   if (vm.count("pager"))
01644   {
01645     if (vm["pager"].as<string>().empty())
01646       opt_nopager= 1;
01647     else
01648     {
01649       opt_nopager= 0;
01650       if (vm[pager].as<string>().length())
01651       {
01652         default_pager_set= 1;
01653         pager= vm["pager"].as<string>();
01654         default_pager= pager;
01655       }
01656       else if (default_pager_set)
01657         pager= default_pager;
01658       else
01659         opt_nopager= 1;
01660     }
01661   }
01662   if (vm.count("disable-pager"))
01663   {
01664     opt_nopager= 1;
01665   }
01666 
01667   if (vm.count("no-auto-rehash"))
01668     opt_rehash= 0;
01669 
01670   if (vm.count("skip-column-names"))
01671     column_names= 0;
01672     
01673   if (vm.count("execute"))
01674   {  
01675     status.setBatch(1);
01676     status.setAddToHistory(1);
01677     if (status.getLineBuff() == NULL)
01678       status.setLineBuff(opt_max_input_line,NULL);
01679     if (status.getLineBuff() == NULL)
01680     {
01681       exit(1);
01682     }
01683     status.getLineBuff()->addString(vm["execute"].as<string>().c_str());
01684   }
01685 
01686   if (one_database)
01687     skip_updates= true;
01688 
01689   if (vm.count("protocol"))
01690   {
01691     boost::to_lower(opt_protocol);
01692     if (not opt_protocol.compare("mysql"))
01693     {
01694       global_con_options= (drizzle_con_options_t)(DRIZZLE_CON_MYSQL|DRIZZLE_CON_INTERACTIVE);
01695       use_drizzle_protocol= false;
01696     }
01697     else if (not opt_protocol.compare("mysql-plugin-auth"))
01698     {
01699       global_con_options= (drizzle_con_options_t)(DRIZZLE_CON_MYSQL|DRIZZLE_CON_INTERACTIVE|DRIZZLE_CON_AUTH_PLUGIN);
01700       use_drizzle_protocol= false;
01701     }
01702     else if (not opt_protocol.compare("drizzle"))
01703     {
01704       global_con_options= (drizzle_con_options_t)(DRIZZLE_CON_EXPERIMENTAL);
01705       use_drizzle_protocol= true;
01706     }
01707     else
01708     {
01709       cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
01710       exit(-1);
01711     }
01712   }
01713  
01714   if (vm.count("port"))
01715   {
01716     opt_drizzle_port= vm["port"].as<uint32_t>();
01717 
01718     /* If the port number is > 65535 it is not a valid port
01719        This also helps with potential data loss casting unsigned long to a
01720        uint32_t. */
01721     if (opt_drizzle_port > 65535)
01722     {
01723       printf(_("Error: Value of %" PRIu32 " supplied for port is not valid.\n"), opt_drizzle_port);
01724       exit(-1);
01725     }
01726   }
01727 
01728   if (vm.count("password"))
01729   {
01730     if (!opt_password.empty())
01731       opt_password.erase();
01732     if (current_password == PASSWORD_SENTINEL)
01733     {
01734       opt_password= "";
01735     }
01736     else
01737     {
01738       opt_password= current_password;
01739       tty_password= false;
01740     }
01741   }
01742   else
01743   {
01744       tty_password= true;
01745   }
01746   
01747 
01748   if (!opt_verbose.empty())
01749   {
01750     verbose= opt_verbose.length();
01751   }
01752 
01753   if (vm.count("batch"))
01754   {
01755     status.setBatch(1);
01756     status.setAddToHistory(0);
01757     if (opt_silent < 1)
01758     {
01759       opt_silent= 1;
01760     }
01761   }
01762   if (vm.count("silent"))
01763   {
01764     opt_silent= 2;
01765   }
01766   
01767   if (vm.count("help") || vm.count("version"))
01768   {
01769     printf(_("Drizzle client %s build %s, for %s-%s (%s) using readline %s\n"),
01770            drizzle_version(), VERSION,
01771            HOST_VENDOR, HOST_OS, HOST_CPU,
01772            rl_library_version);
01773     if (vm.count("version"))
01774       exit(0);
01775     printf(_("Copyright (C) 2008 Sun Microsystems\n"
01776            "This software comes with ABSOLUTELY NO WARRANTY. "
01777            "This is free software,\n"
01778            "and you are welcome to modify and redistribute it "
01779            "under the GPL license\n"));
01780     printf(_("Usage: drizzle [OPTIONS] [schema]\n"));
01781     cout << long_options;
01782     exit(0);
01783   }
01784  
01785 
01786   if (process_options())
01787   {
01788     exit(1);
01789   }
01790 
01791   memset(&drizzle, 0, sizeof(drizzle));
01792   if (sql_connect(current_host, current_db, current_user, opt_password))
01793   {
01794     quick= 1;          // Avoid history
01795     status.setExitStatus(1);
01796     drizzle_end(-1);
01797   }
01798 
01799   int command_error;
01800   if (execute_commands(&command_error) != false)
01801   {
01802     /* we've executed a command so exit before we go into readline mode */
01803     exit(command_error);
01804   }
01805 
01806   if (status.getBatch() && !status.getLineBuff())
01807   {
01808     status.setLineBuff(opt_max_input_line, stdin);
01809     if (status.getLineBuff() == NULL)
01810     {
01811       exit(1);
01812     }
01813   }
01814 
01815   if (!status.getBatch())
01816     ignore_errors=1;        // Don't abort monitor
01817 
01818   if (opt_sigint_ignore)
01819     signal(SIGINT, SIG_IGN);
01820   else
01821     signal(SIGINT, handle_sigint);              // Catch SIGINT to clean up
01822   signal(SIGQUIT, drizzle_end);      // Catch SIGQUIT to clean up
01823 
01824 #if defined(HAVE_TERMIOS_H) && defined(GWINSZ_IN_SYS_IOCTL)
01825   /* Readline will call this if it installs a handler */
01826   signal(SIGWINCH, window_resize);
01827   /* call the SIGWINCH handler to get the default term width */
01828   window_resize(0);
01829 #endif
01830   std::vector<char> output_buff;
01831   output_buff.resize(512);
01832 
01833   snprintf(&output_buff[0], output_buff.size(), 
01834            _("Welcome to the Drizzle client..  Commands end with %s or \\g."), 
01835            delimiter);
01836 
01837   put_info(&output_buff[0], INFO_INFO, 0, 0);
01838 
01839   glob_buffer= new string();
01840   glob_buffer->reserve(512);
01841 
01842   snprintf(&output_buff[0], output_buff.size(),
01843            _("Your Drizzle connection id is %u\nConnection protocol: %s\nServer version: %s\n"),
01844            drizzle_con_thread_id(con),
01845            opt_protocol.c_str(),
01846            server_version_string(con));
01847   put_info(&output_buff[0], INFO_INFO, 0, 0);
01848 
01849 
01850   initialize_readline((char *)current_prompt.c_str());
01851   if (!status.getBatch() && !quick)
01852   {
01853     /* read-history from file, default ~/.drizzle_history*/
01854     if (getenv("DRIZZLE_HISTFILE"))
01855       histfile= strdup(getenv("DRIZZLE_HISTFILE"));
01856     else if (getenv("HOME"))
01857     {
01858       histfile=(char*) malloc(strlen(getenv("HOME")) + strlen("/.drizzle_history") + 2);
01859       if (histfile)
01860         sprintf(histfile,"%s/.drizzle_history",getenv("HOME"));
01861       char link_name[FN_REFLEN];
01862       ssize_t sym_link_size= readlink(histfile,link_name,FN_REFLEN-1);
01863       if (sym_link_size >= 0)
01864       {
01865         link_name[sym_link_size]= '\0';
01866         if (strncmp(link_name, "/dev/null", 10) == 0)
01867         {
01868           /* The .drizzle_history file is a symlink to /dev/null, don't use it */
01869           free(histfile);
01870           histfile= 0;
01871         }
01872       }
01873     }
01874     if (histfile)
01875     {
01876       if (verbose)
01877         tee_fprintf(stdout, _("Reading history-file %s\n"),histfile);
01878       read_history(histfile);
01879       histfile_tmp= (char*) malloc((uint32_t) strlen(histfile) + 5);
01880       sprintf(histfile_tmp, "%s.TMP", histfile);
01881     }
01882   }
01883 
01884   put_info(_("Type 'help;' or '\\h' for help. "
01885              "Type '\\c' to clear the buffer.\n"),INFO_INFO,0,0);
01886   status.setExitStatus(read_and_execute(!status.getBatch()));
01887   if (opt_outfile)
01888     end_tee();
01889   drizzle_end(0);
01890 }
01891 
01892   catch(exception &err)
01893   {
01894     cerr << _("Error:") << err.what() << endl;
01895   }
01896   return(0);        // Keep compiler happy
01897 }
01898 
01899 void drizzle_end(int sig)
01900 {
01901   drizzle_con_free(con);
01902   drizzle_free(drizzle);
01903   if (!status.getBatch() && !quick && histfile)
01904   {
01905     /* write-history */
01906     if (verbose)
01907       tee_fprintf(stdout, _("Writing history-file %s\n"),histfile);
01908     if (!write_history(histfile_tmp))
01909       rename(histfile_tmp, histfile);
01910   }
01911   delete status.getLineBuff();
01912   status.setLineBuff(0);
01913 
01914   if (sig >= 0)
01915     put_info(sig ? _("Aborted") : _("Bye"), INFO_RESULT,0,0);
01916   delete glob_buffer;
01917   delete processed_prompt;
01918   opt_password.erase();
01919   free(histfile);
01920   free(histfile_tmp);
01921   current_db.erase();
01922   current_host.erase();
01923   current_user.erase();
01924   free(full_username);
01925   free(part_username);
01926   free(default_prompt);
01927   current_prompt.erase();
01928   exit(status.getExitStatus());
01929 }
01930 
01931 
01932 /*
01933   This function handles sigint calls
01934   If query is in process, kill query
01935   no query in process, terminate like previous behavior
01936 */
01937 extern "C"
01938 void handle_sigint(int sig)
01939 {
01940   /* terminate if no query being executed, or we already tried interrupting */
01941   if (executing_query == false or interrupted_query)
01942   { }
01943   else if (drizzle)
01944   {
01945     drizzle_con_st *kill_drizzle_con;
01946     if ((kill_drizzle_con= drizzle_con_add_tcp(drizzle,
01947                                                current_host.c_str(), opt_drizzle_port,
01948                                                current_user.c_str(), opt_password.c_str(), NULL,
01949                                                use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL)))
01950     {
01951       /* kill_buffer is always big enough because max length of %lu is 15 */
01952       char kill_buffer[40];
01953       snprintf(kill_buffer, sizeof(kill_buffer), "KILL /*!50000 QUERY */ %u", drizzle_con_thread_id(kill_drizzle_con));
01954 
01955       drizzle_return_t ret;
01956       drizzle_result_st res;
01957       if ((drizzle_query_str(kill_drizzle_con, &res, kill_buffer, &ret)))
01958       {
01959         drizzle_result_free(&res);
01960       }
01961 
01962       drizzle_con_free(kill_drizzle_con);
01963 
01964       tee_fprintf(stdout, _("Query aborted by Ctrl+C\n"));
01965 
01966       interrupted_query= true;
01967 
01968       return;
01969     }
01970   }
01971 
01972   drizzle_end(sig);
01973 }
01974 
01975 
01976 #if defined(HAVE_TERMIOS_H) && defined(GWINSZ_IN_SYS_IOCTL)
01977 void window_resize(int)
01978 {
01979   struct winsize window_size;
01980 
01981   if (ioctl(fileno(stdin), TIOCGWINSZ, &window_size) == 0)
01982     terminal_width= window_size.ws_col;
01983 }
01984 #endif
01985 
01986 
01987 
01988 static int process_options()
01989 {
01990   if (const char* tmp= getenv("DRIZZLE_HOST"))
01991     current_host= tmp;
01992 
01993   if (const char* pagpoint= getenv("PAGER"))
01994   {
01995     pager= pagpoint;
01996   }
01997   else
01998   {
01999     pager= "stdout";
02000     opt_nopager= 1;
02001   }
02002   default_pager= pager;
02003 
02004   //
02005 
02006   if (status.getBatch()) /* disable pager and outfile in this case */
02007   {
02008     default_pager= "stdout";
02009     pager= "stdout";
02010     opt_nopager= 1;
02011     default_pager_set= 0;
02012     opt_outfile= 0;
02013     opt_reconnect= 0;
02014   }
02015 
02016   if (tty_password)
02017     opt_password= client_get_tty_password(NULL);
02018   return(0);
02019 }
02020 
02021 static int read_and_execute(bool interactive)
02022 {
02023   char *line;
02024   char in_string=0;
02025   uint32_t line_number=0;
02026   bool ml_comment= 0;
02027   Commands *com;
02028   status.setExitStatus(1);
02029 
02030   for (;;)
02031   {
02032     if (!interactive)
02033     {
02034       if (status.getLineBuff())
02035         line= status.getLineBuff()->readline();
02036       else
02037         line= 0;
02038 
02039       line_number++;
02040       if (show_progress_size > 0)
02041       {
02042         if ((line_number % show_progress_size) == 0)
02043           fprintf(stderr, _("Processing line: %"PRIu32"\n"), line_number);
02044       }
02045       if (!glob_buffer->empty())
02046         status.setQueryStartLine(line_number);
02047     }
02048     else
02049     {
02050       string prompt(ml_comment
02051                       ? "   /*> " 
02052                       : glob_buffer->empty()
02053                         ? construct_prompt()
02054                         : not in_string
02055                           ? "    -> "
02056                           : in_string == '\''
02057                             ? "    '> "
02058                             : in_string == '`'
02059                               ? "    `> "
02060                               : "    \"> ");
02061       if (opt_outfile && glob_buffer->empty())
02062         fflush(OUTFILE);
02063 
02064       if (opt_outfile)
02065         fputs(prompt.c_str(), OUTFILE);
02066       line= readline(prompt.c_str());
02067       /*
02068         When Ctrl+d or Ctrl+z is pressed, the line may be NULL on some OS
02069         which may cause coredump.
02070       */
02071       if (opt_outfile && line)
02072         fprintf(OUTFILE, "%s\n", line);
02073     }
02074     // End of file
02075     if (!line)
02076     {
02077       status.setExitStatus(0);
02078       break;
02079     }
02080 
02081     /*
02082       Check if line is a drizzle command line
02083       (We want to allow help, print and clear anywhere at line start
02084     */
02085     if ((named_cmds || (glob_buffer->empty()))
02086         && !ml_comment && !in_string && (com=find_command(line,0)))
02087     {
02088       if ((*com->func)(glob_buffer,line) > 0)
02089         break;
02090       // If buffer was emptied
02091       if (glob_buffer->empty())
02092         in_string=0;
02093       if (interactive && status.getAddToHistory() && not_in_history(line))
02094         add_history(line);
02095       continue;
02096     }
02097     if (add_line(glob_buffer,line,&in_string,&ml_comment))
02098       break;
02099   }
02100   /* if in batch mode, send last query even if it doesn't end with \g or go */
02101 
02102   if (!interactive && !status.getExitStatus())
02103   {
02104     remove_cntrl(glob_buffer);
02105     if (!glob_buffer->empty())
02106     {
02107       status.setExitStatus(1);
02108       if (com_go(glob_buffer,line) <= 0)
02109         status.setExitStatus(0);
02110     }
02111   }
02112 
02113   return status.getExitStatus();
02114 }
02115 
02116 
02117 static Commands *find_command(const char *name,char cmd_char)
02118 {
02119   uint32_t len;
02120   const char *end;
02121 
02122   if (!name)
02123   {
02124     len=0;
02125     end=0;
02126   }
02127   else
02128   {
02129     while (isspace(*name))
02130       name++;
02131     /*
02132       If there is an \\g in the row or if the row has a delimiter but
02133       this is not a delimiter command, let add_line() take care of
02134       parsing the row and calling find_command()
02135     */
02136     if (strstr(name, "\\g") || (strstr(name, delimiter) &&
02137                                 !(strlen(name) >= 9 &&
02138                                   !strcmp(name, "delimiter"))))
02139       return(NULL);
02140     if ((end=strcont(name," \t")))
02141     {
02142       len=(uint32_t) (end - name);
02143       while (isspace(*end))
02144         end++;
02145       if (!*end)
02146         end=0;          // no arguments to function
02147     }
02148     else
02149       len=(uint32_t) strlen(name);
02150   }
02151 
02152   for (uint32_t i= 0; commands[i].getName(); i++)
02153   {
02154     if (commands[i].func &&
02155         ((name && !strncmp(name, commands[i].getName(), len)
02156           && !commands[i].getName()[len] && (!end || (end && commands[i].getTakesParams()))) || (!name && commands[i].getCmdChar() == cmd_char)))
02157     {
02158       return(&commands[i]);
02159     }
02160   }
02161   return(NULL);
02162 }
02163 
02164 
02165 static bool add_line(string *buffer, char *line, char *in_string,
02166                         bool *ml_comment)
02167 {
02168   unsigned char inchar;
02169   char *pos, *out;
02170   Commands *com;
02171   bool need_space= 0;
02172   bool ss_comment= 0;
02173 
02174 
02175   if (!line[0] && (buffer->empty()))
02176     return(0);
02177   if (status.getAddToHistory() && line[0] && not_in_history(line))
02178     add_history(line);
02179 
02180   for (pos=out=line ; (inchar= (unsigned char) *pos) ; pos++)
02181   {
02182     if (!preserve_comments)
02183     {
02184       // Skip spaces at the beggining of a statement
02185       if (isspace(inchar) && (out == line) &&
02186           (buffer->empty()))
02187         continue;
02188     }
02189 
02190     // Accept multi-byte characters as-is
02191     if (not drizzled::utf8::is_single(*pos))
02192     {
02193       int length;
02194       if ((length= drizzled::utf8::sequence_length(*pos)))
02195       {
02196         if (!*ml_comment || preserve_comments)
02197         {
02198           while (length--)
02199             *out++ = *pos++;
02200           pos--;
02201         }
02202         else
02203           pos+= length - 1;
02204         continue;
02205       }
02206     }
02207     if (!*ml_comment && inchar == '\\' &&
02208         !(*in_string && (drizzle_con_status(con) & DRIZZLE_CON_STATUS_NO_BACKSLASH_ESCAPES)))
02209     {
02210       // Found possbile one character command like \c
02211 
02212       if (!(inchar = (unsigned char) *++pos))
02213         break;        // readline adds one '\'
02214       if (*in_string || inchar == 'N')  // \N is short for NULL
02215       {          // Don't allow commands in string
02216         *out++='\\';
02217         *out++= (char) inchar;
02218         continue;
02219       }
02220       if ((com=find_command(NULL,(char) inchar)))
02221       {
02222         // Flush previously accepted characters
02223         if (out != line)
02224         {
02225           buffer->append(line, (out-line));
02226           out= line;
02227         }
02228 
02229         if ((*com->func)(buffer,pos-1) > 0)
02230           return(1);                       // Quit
02231         if (com->getTakesParams())
02232         {
02233           if (ss_comment)
02234           {
02235             /*
02236               If a client-side macro appears inside a server-side comment,
02237               discard all characters in the comment after the macro (that is,
02238               until the end of the comment rather than the next delimiter)
02239             */
02240             for (pos++; *pos && (*pos != '*' || *(pos + 1) != '/'); pos++)
02241               ;
02242             pos--;
02243           }
02244           else
02245           {
02246             for (pos++ ;
02247                  *pos && (*pos != *delimiter ||
02248                           strncmp(pos + 1, delimiter + 1,
02249                                   strlen(delimiter + 1))) ; pos++)
02250               ;  // Remove parameters
02251             if (!*pos)
02252               pos--;
02253             else
02254               pos+= delimiter_length - 1; // Point at last delim char
02255           }
02256         }
02257       }
02258       else
02259       {
02260         string buff(_("Unknown command: "));
02261         buff.push_back('\'');
02262         buff.push_back(inchar);
02263         buff.push_back('\'');
02264         buff.push_back('.');
02265         if (put_info(buff.c_str(),INFO_ERROR,0,0) > 0)
02266           return(1);
02267         *out++='\\';
02268         *out++=(char) inchar;
02269         continue;
02270       }
02271     }
02272     else if (!*ml_comment && !*in_string && !strncmp(pos, delimiter,
02273                                                      strlen(delimiter)))
02274     {
02275       // Found a statement. Continue parsing after the delimiter
02276       pos+= delimiter_length;
02277 
02278       if (preserve_comments)
02279       {
02280         while (isspace(*pos))
02281           *out++= *pos++;
02282       }
02283       // Flush previously accepted characters
02284       if (out != line)
02285       {
02286         buffer->append(line, (out-line));
02287         out= line;
02288       }
02289 
02290       if (preserve_comments && ((*pos == '#') ||
02291                                 ((*pos == '-') &&
02292                                  (pos[1] == '-') &&
02293                                  isspace(pos[2]))))
02294       {
02295         // Add trailing single line comments to this statement
02296         buffer->append(pos);
02297         pos+= strlen(pos);
02298       }
02299 
02300       pos--;
02301 
02302       if ((com= find_command(buffer->c_str(), 0)))
02303       {
02304 
02305         if ((*com->func)(buffer, buffer->c_str()) > 0)
02306           return(1);                       // Quit
02307       }
02308       else
02309       {
02310         if (com_go(buffer, 0) > 0)             // < 0 is not fatal
02311           return(1);
02312       }
02313       buffer->clear();
02314     }
02315     else if (!*ml_comment
02316              && (!*in_string
02317                  && (inchar == '#'
02318                      || (inchar == '-'
02319                          && pos[1] == '-'
02320                          && isspace(pos[2])))))
02321     {
02322       // Flush previously accepted characters
02323       if (out != line)
02324       {
02325         buffer->append(line, (out - line));
02326         out= line;
02327       }
02328 
02329       // comment to end of line
02330       if (preserve_comments)
02331       {
02332         bool started_with_nothing= !buffer->empty();
02333         buffer->append(pos);
02334 
02335         /*
02336           A single-line comment by itself gets sent immediately so that
02337           client commands (delimiter, status, etc) will be interpreted on
02338           the next line.
02339         */
02340         if (started_with_nothing)
02341         {
02342           if (com_go(buffer, 0) > 0)             // < 0 is not fatal
02343            return 1;
02344           buffer->clear();
02345         }
02346       }  
02347 
02348       break;
02349     }
02350     else if (!*in_string && inchar == '/' && *(pos+1) == '*' &&
02351              *(pos+2) != '!')
02352     {
02353       if (preserve_comments)
02354       {
02355         *out++= *pos++;                       // copy '/'
02356         *out++= *pos;                         // copy '*'
02357       }
02358       else
02359         pos++;
02360       *ml_comment= 1;
02361       if (out != line)
02362       {
02363         buffer->append(line, (out-line));
02364         out=line;
02365       }
02366     }
02367     else if (*ml_comment && !ss_comment && inchar == '*' && *(pos + 1) == '/')
02368     {
02369       if (preserve_comments)
02370       {
02371         *out++= *pos++;                       // copy '*'
02372         *out++= *pos;                         // copy '/'
02373       }
02374       else
02375         pos++;
02376       *ml_comment= 0;
02377       if (out != line)
02378       {
02379         buffer->append(line, (out - line));
02380         out= line;
02381       }
02382       // Consumed a 2 chars or more, and will add 1 at most,
02383       // so using the 'line' buffer to edit data in place is ok.
02384       need_space= 1;
02385     }
02386     else
02387     {
02388       // Add found char to buffer
02389       if (!*in_string && inchar == '/' && *(pos + 1) == '*' &&
02390           *(pos + 2) == '!')
02391         ss_comment= 1;
02392       else if (!*in_string && ss_comment && inchar == '*' && *(pos + 1) == '/')
02393         ss_comment= 0;
02394       if (inchar == *in_string)
02395         *in_string= 0;
02396       else if (!*ml_comment && !*in_string &&
02397                (inchar == '\'' || inchar == '"' || inchar == '`'))
02398         *in_string= (char) inchar;
02399       if (!*ml_comment || preserve_comments)
02400       {
02401         if (need_space && !isspace((char)inchar))
02402           *out++= ' ';
02403         need_space= 0;
02404         *out++= (char) inchar;
02405       }
02406     }
02407   }
02408   if (out != line || (buffer->length() > 0))
02409   {
02410     *out++='\n';
02411     uint32_t length=(uint32_t) (out-line);
02412     if ((buffer->length() + length) > opt_max_input_line)
02413     {
02414       status.setExitStatus(1);
02415       put_info(_("Not found a delimiter within max_input_line of input"), INFO_ERROR, 0, 0);
02416       return 1;
02417     }
02418     if ((!*ml_comment || preserve_comments))
02419       buffer->append(line, length);
02420   }
02421   return(0);
02422 }
02423 
02424 /*****************************************************************
02425             Interface to Readline Completion
02426 ******************************************************************/
02427 
02428 
02429 static char **mysql_completion (const char *text, int start, int end);
02430 extern "C" char *new_command_generator(const char *text, int);
02431 
02432 /*
02433   Tell the GNU Readline library how to complete.  We want to try to complete
02434   on command names if this is the first word in the line, or on filenames
02435   if not.
02436 */
02437 static char *no_completion(const char *, int)
02438 {
02439   /* No filename completion */
02440   return 0;
02441 }
02442 
02443 
02444 /* glues pieces of history back together if in pieces   */
02445 static void fix_history(string *final_command)
02446 {
02447   int total_lines = 1;
02448   const char *ptr = final_command->c_str();
02449   char str_char = '\0';  /* Character if we are in a string or not */
02450 
02451   /* Converted buffer */
02452   string fixed_buffer;
02453   fixed_buffer.reserve(512);
02454 
02455   /* find out how many lines we have and remove newlines */
02456   while (*ptr != '\0')
02457   {
02458     switch (*ptr) {
02459       /* string character */
02460     case '"':
02461     case '\'':
02462     case '`':
02463       // open string
02464       if (str_char == '\0')
02465         str_char = *ptr;
02466       else if (str_char == *ptr)   /* close string */
02467         str_char = '\0';
02468       fixed_buffer.append(ptr, 1);
02469       break;
02470     case '\n':
02471       /*
02472         not in string, change to space
02473         if in string, leave it alone
02474       */
02475       fixed_buffer.append((str_char == '\0') ? " " : "\n");
02476       total_lines++;
02477       break;
02478     case '\\':
02479       fixed_buffer.append("\\");
02480       /* need to see if the backslash is escaping anything */
02481       if (str_char)
02482       {
02483         ptr++;
02484         /* special characters that need escaping */
02485         if (*ptr == '\'' || *ptr == '"' || *ptr == '\\')
02486           fixed_buffer.append(ptr, 1);
02487         else
02488           ptr--;
02489       }
02490       break;
02491     default:
02492       fixed_buffer.append(ptr, 1);
02493     }
02494     ptr++;
02495   }
02496   if (total_lines > 1)
02497     add_history(fixed_buffer.c_str());
02498 }
02499 
02500 /*
02501   returns 0 if line matches the previous history entry
02502   returns 1 if the line doesn't match the previous history entry
02503 */
02504 static int not_in_history(const char *line)
02505 {
02506   HIST_ENTRY *oldhist = history_get(history_length);
02507 
02508   if (oldhist == 0)
02509     return 1;
02510   if (strcmp(oldhist->line,line) == 0)
02511     return 0;
02512   return 1;
02513 }
02514 
02515 static void initialize_readline (char *name)
02516 {
02517   /* Allow conditional parsing of the ~/.inputrc file. */
02518   rl_readline_name= name;
02519 
02520   /* Tell the completer that we want a crack first. */
02521   rl_attempted_completion_function= (rl_completion_func_t*)&mysql_completion;
02522   rl_completion_entry_function= (drizzle_compentry_func_t*)&no_completion;
02523 }
02524 
02525 
02526 /*
02527   Attempt to complete on the contents of TEXT.  START and END show the
02528   region of TEXT that contains the word to complete.  We can use the
02529   entire line in case we want to do some simple parsing.  Return the
02530   array of matches, or NULL if there aren't any.
02531 */
02532 char **mysql_completion (const char *text, int, int)
02533 {
02534   if (!status.getBatch() && !quick)
02535     return rl_completion_matches(text, new_command_generator);
02536   else
02537     return (char**) 0;
02538 }
02539 
02540 inline string lower_string(const string& from)
02541 {
02542   return boost::to_lower_copy(from);
02543 }
02544 
02545 inline string lower_string(const char* from)
02546 {
02547   return boost::to_lower_copy(string(from));
02548 }
02549 
02550 template <class T>
02551 class CompletionMatch :
02552   public unary_function<const string&, bool>
02553 {
02554   string match_text; 
02555   T match_func;
02556 public:
02557   CompletionMatch(string text) : match_text(text) {}
02558   inline bool operator() (const pair<string,string> &match_against) const
02559   {
02560     string sub_match= lower_string(match_against.first.substr(0,match_text.size()));
02561     return match_func(sub_match,match_text);
02562   }
02563 };
02564 
02565 
02566 
02567 extern "C"
02568 char *new_command_generator(const char *text, int state)
02569 {
02570 
02571   if (!state)
02572   {
02573     completion_string= lower_string(text);
02574     if (completion_string.size() == 0)
02575     {
02576       completion_iter= completion_map.begin();
02577       completion_end= completion_map.end();
02578     }
02579     else
02580     {
02581       completion_iter= find_if(completion_map.begin(), completion_map.end(),
02582                                CompletionMatch<equal_to<string> >(completion_string));
02583       completion_end= find_if(completion_iter, completion_map.end(),
02584                               CompletionMatch<not_equal_to<string> >(completion_string));
02585     }
02586   }
02587   if (completion_iter == completion_end || (size_t)state > completion_map.size())
02588     return NULL;
02589   char *result= (char *)malloc((*completion_iter).second.size()+1);
02590   strcpy(result, (*completion_iter).second.c_str());
02591   completion_iter++;
02592   return result;
02593 }
02594 
02595 /* Build up the completion hash */
02596 
02597 static void build_completion_hash(bool rehash, bool write_info)
02598 {
02599   Commands *cmd=commands;
02600   drizzle_return_t ret;
02601   drizzle_result_st databases,tables,fields;
02602   drizzle_row_t database_row,table_row;
02603   string tmp_str, tmp_str_lower;
02604   std::string query;
02605 
02606   if (status.getBatch() || quick || current_db.empty())
02607     return;      // We don't need completion in batches
02608   if (!rehash)
02609     return;
02610 
02611   completion_map.clear();
02612 
02613   /* hash this file's known subset of SQL commands */
02614   while (cmd->getName()) {
02615     tmp_str= cmd->getName();
02616     tmp_str_lower= lower_string(tmp_str);
02617     completion_map[tmp_str_lower]= tmp_str;
02618     cmd++;
02619   }
02620 
02621   /* hash Drizzle functions (to be implemented) */
02622 
02623   /* hash all database names */
02624   if (drizzle_query_str(con, &databases, "select schema_name from information_schema.schemata", &ret) != NULL)
02625   {
02626     if (ret == DRIZZLE_RETURN_OK)
02627     {
02628       if (drizzle_result_buffer(&databases) != DRIZZLE_RETURN_OK)
02629       {
02630         put_info(drizzle_error(drizzle),INFO_INFO,0,0);
02631       }
02632       else
02633       {
02634         while ((database_row=drizzle_row_next(&databases)))
02635         {
02636           tmp_str= database_row[0];
02637           tmp_str_lower= lower_string(tmp_str);
02638           completion_map[tmp_str_lower]= tmp_str;
02639         }
02640       }
02641     }
02642 
02643     drizzle_result_free(&databases);
02644   }
02645 
02646   query= "select table_name, column_name from information_schema.columns where table_schema='";
02647   query.append(current_db);
02648   query.append("' order by table_name");
02649   
02650   if (drizzle_query(con, &fields, query.c_str(), query.length(), &ret) != NULL)
02651   {
02652     if (ret == DRIZZLE_RETURN_OK &&
02653         drizzle_result_buffer(&fields) == DRIZZLE_RETURN_OK)
02654     {
02655       if (drizzle_result_row_count(&tables) > 0 && !opt_silent && write_info)
02656       {
02657         tee_fprintf(stdout,
02658                     _("Reading table information for completion of "
02659                       "table and column names\n"
02660                       "You can turn off this feature to get a quicker "
02661                       "startup with -A\n\n"));
02662       }
02663 
02664       std::string table_name;
02665       while ((table_row=drizzle_row_next(&fields)))
02666       {
02667         if (table_name.compare(table_row[0]) != 0)
02668         {
02669           tmp_str= table_row[0];
02670           tmp_str_lower= lower_string(tmp_str);
02671           completion_map[tmp_str_lower]= tmp_str;
02672           table_name= table_row[0];
02673         }
02674         tmp_str= table_row[0];
02675         tmp_str.append(".");
02676         tmp_str.append(table_row[1]);
02677         tmp_str_lower= lower_string(tmp_str);
02678         completion_map[tmp_str_lower]= tmp_str;
02679 
02680         tmp_str= table_row[1];
02681         tmp_str_lower= lower_string(tmp_str);
02682         completion_map[tmp_str_lower]= tmp_str;
02683       }
02684     }
02685   }
02686   drizzle_result_free(&fields);
02687   completion_iter= completion_map.begin();
02688 }
02689 
02690 /* for gnu readline */
02691 
02692 
02693 static int reconnect(void)
02694 {
02695   if (opt_reconnect)
02696   {
02697     put_info(_("No connection. Trying to reconnect..."),INFO_INFO,0,0);
02698     (void) com_connect((string *)0, 0);
02699     if (opt_rehash && connected)
02700       com_rehash(NULL, NULL);
02701   }
02702   if (! connected)
02703     return put_info(_("Can't connect to the server\n"),INFO_ERROR,0,0);
02704   return 0;
02705 }
02706 
02707 static void get_current_db(void)
02708 {
02709   drizzle_return_t ret;
02710   drizzle_result_st res;
02711 
02712   current_db.erase();
02713   current_db= "";
02714   /* In case of error below current_db will be NULL */
02715   if (drizzle_query_str(con, &res, "SELECT DATABASE()", &ret) != NULL)
02716   {
02717     if (ret == DRIZZLE_RETURN_OK &&
02718         drizzle_result_buffer(&res) == DRIZZLE_RETURN_OK)
02719     {
02720       drizzle_row_t row= drizzle_row_next(&res);
02721       if (row[0])
02722         current_db= row[0];
02723       drizzle_result_free(&res);
02724     }
02725   }
02726 }
02727 
02728 /***************************************************************************
02729  The different commands
02730 ***************************************************************************/
02731 
02732 int drizzleclient_real_query_for_lazy(const char *buf, size_t length,
02733                                       drizzle_result_st *result,
02734                                       uint32_t *error_code)
02735 {
02736   drizzle_return_t ret;
02737 
02738   for (uint32_t retry=0;; retry++)
02739   {
02740     int error;
02741     if (drizzle_query(con, result, buf, length, &ret) != NULL and
02742         ret == DRIZZLE_RETURN_OK)
02743     {
02744       return 0;
02745     }
02746     error= put_error(con, result);
02747 
02748     if (ret == DRIZZLE_RETURN_ERROR_CODE)
02749     {
02750       *error_code= drizzle_result_error_code(result);
02751       drizzle_result_free(result);
02752     }
02753 
02754     if (ret != DRIZZLE_RETURN_LOST_CONNECTION || retry > 1 ||
02755         !opt_reconnect)
02756     {
02757       return error;
02758     }
02759 
02760     if (reconnect())
02761       return error;
02762   }
02763 }
02764 
02765 int drizzleclient_store_result_for_lazy(drizzle_result_st *result)
02766 {
02767   if (drizzle_result_buffer(result) == DRIZZLE_RETURN_OK)
02768   {
02769     return 0;
02770   }
02771 
02772   if (drizzle_con_error(con)[0])
02773   {
02774     int ret= put_error(con, result);
02775     drizzle_result_free(result);
02776     return ret;
02777   }
02778 
02779   return 0;
02780 }
02781 
02782 static int
02783 com_help(string *buffer, const char *)
02784 {
02785   int i, j;
02786   char buff[32], *end;
02787   std::vector<char> output_buff;
02788   output_buff.resize(512);
02789 
02790   put_info(_("List of all Drizzle commands:"), INFO_INFO,0,0);
02791   if (!named_cmds)
02792   {
02793     snprintf(&output_buff[0], output_buff.size(),
02794              _("Note that all text commands must be first on line and end with '%s' or \\g"),
02795              delimiter);
02796     put_info(&output_buff[0], INFO_INFO, 0, 0);
02797   }
02798   for (i = 0; commands[i].getName(); i++)
02799   {
02800     end= strcpy(buff, commands[i].getName());
02801     end+= strlen(commands[i].getName());
02802     for (j= (int)strlen(commands[i].getName()); j < 10; j++)
02803       end= strcpy(end, " ")+1;
02804     if (commands[i].func)
02805       tee_fprintf(stdout, "%s(\\%c) %s\n", buff,
02806                   commands[i].getCmdChar(), _(commands[i].getDoc()));
02807   }
02808   tee_fprintf(stdout, "\n");
02809   buffer->clear();
02810   return 0;
02811 }
02812 
02813 
02814 static int
02815 com_clear(string *buffer, const char *)
02816 {
02817   if (status.getAddToHistory())
02818     fix_history(buffer);
02819   buffer->clear();
02820   return 0;
02821 }
02822 
02823 
02824 /*
02825   Execute command
02826   Returns: 0  if ok
02827   -1 if not fatal error
02828   1  if fatal error
02829 */
02830 static int
02831 com_go(string *buffer, const char *)
02832 {
02833   char          buff[200]; /* about 110 chars used so far */
02834   drizzle_result_st result;
02835   drizzle_return_t ret;
02836   uint32_t      warnings= 0;
02837   boost::posix_time::ptime timer;
02838   uint32_t      error= 0;
02839   uint32_t      error_code= 0;
02840   int           err= 0;
02841 
02842   interrupted_query= false;
02843 
02844   /* Remove garbage for nicer messages */
02845   remove_cntrl(buffer);
02846 
02847   if (buffer->empty())
02848   {
02849     // Ignore empty quries
02850     if (status.getBatch())
02851       return 0;
02852     return put_info(_("No query specified\n"),INFO_ERROR,0,0);
02853 
02854   }
02855   if (!connected && reconnect())
02856   {
02857     // Remove query on error
02858     buffer->clear();
02859     return opt_reconnect ? -1 : 1;          // Fatal error
02860   }
02861   if (verbose)
02862     (void) com_print(buffer, 0);
02863 
02864   if (skip_updates &&
02865       ((buffer->length() < 4) || (buffer->find( "SET ") != 0)))
02866   {
02867     (void) put_info(_("Ignoring query to other database"),INFO_INFO,0,0);
02868     return 0;
02869   }
02870 
02871   timer=start_timer();
02872   executing_query= true;
02873   error= drizzleclient_real_query_for_lazy(buffer->c_str(),buffer->length(),&result, &error_code);
02874 
02875   if (status.getAddToHistory())
02876   {
02877     buffer->append(vertical ? "\\G" : delimiter);
02878     /* Append final command onto history */
02879     fix_history(buffer);
02880   }
02881 
02882   buffer->clear();
02883 
02884   if (error)
02885     goto end;
02886 
02887   do
02888   {
02889     char *pos;
02890 
02891     if (quick)
02892     {
02893       if (drizzle_column_buffer(&result) != DRIZZLE_RETURN_OK)
02894       {
02895         error= put_error(con, &result);
02896         goto end;
02897       }
02898     }
02899     else
02900     {
02901       error= drizzleclient_store_result_for_lazy(&result);
02902       if (error)
02903         goto end;
02904     }
02905 
02906     string time_buff("");
02907     if (verbose >= 3 || !opt_silent)
02908       drizzle_end_timer(timer,time_buff);
02909 
02910     /* Every branch must truncate  buff . */
02911     if (drizzle_result_column_count(&result) > 0)
02912     {
02913       if (!quick && drizzle_result_row_count(&result) == 0 &&
02914           !column_types_flag)
02915       {
02916         strcpy(buff, _("Empty set"));
02917       }
02918       else
02919       {
02920         init_pager();
02921         if (vertical || (auto_vertical_output &&
02922                          (terminal_width < get_result_width(&result))))
02923           print_table_data_vertically(&result);
02924         else if (opt_silent && verbose <= 2 && !output_tables)
02925           print_tab_data(&result);
02926         else
02927           print_table_data(&result);
02928         sprintf(buff,
02929                 ngettext("%ld row in set","%ld rows in set",
02930                          (long) drizzle_result_row_count(&result)),
02931                 (long) drizzle_result_row_count(&result));
02932         end_pager();
02933         if (drizzle_result_error_code(&result))
02934           error= put_error(con, &result);
02935       }
02936     }
02937     else if (drizzle_result_affected_rows(&result) == ~(uint64_t) 0)
02938       strcpy(buff,_("Query OK"));
02939     else
02940       sprintf(buff, ngettext("Query OK, %ld row affected",
02941                              "Query OK, %ld rows affected",
02942                              (long) drizzle_result_affected_rows(&result)),
02943               (long) drizzle_result_affected_rows(&result));
02944 
02945     pos= strchr(buff, '\0');
02946     if ((warnings= drizzle_result_warning_count(&result)))
02947     {
02948       *pos++= ',';
02949       *pos++= ' ';
02950       char warnings_buff[20];
02951       memset(warnings_buff,0,20);
02952       sprintf(warnings_buff, "%d", warnings);
02953       strcpy(pos, warnings_buff);
02954       pos+= strlen(warnings_buff);
02955       pos= strcpy(pos, " warning")+8;
02956       if (warnings != 1)
02957         *pos++= 's';
02958     }
02959     strcpy(pos, time_buff.c_str());
02960     put_info(buff,INFO_RESULT,0,0);
02961     if (strcmp(drizzle_result_info(&result), ""))
02962       put_info(drizzle_result_info(&result),INFO_RESULT,0,0);
02963     put_info("",INFO_RESULT,0,0);      // Empty row
02964 
02965     if (unbuffered)
02966       fflush(stdout);
02967     drizzle_result_free(&result);
02968 
02969     if (drizzle_con_status(con) & DRIZZLE_CON_STATUS_MORE_RESULTS_EXISTS)
02970     {
02971       if (drizzle_result_read(con, &result, &ret) == NULL ||
02972           ret != DRIZZLE_RETURN_OK)
02973       {
02974         if (ret == DRIZZLE_RETURN_ERROR_CODE)
02975         {
02976           error_code= drizzle_result_error_code(&result);
02977           drizzle_result_free(&result);
02978         }
02979 
02980         error= put_error(con, NULL);
02981         goto end;
02982       }
02983     }
02984 
02985   } while (drizzle_con_status(con) & DRIZZLE_CON_STATUS_MORE_RESULTS_EXISTS);
02986   if (err >= 1)
02987   {
02988     error= put_error(con, NULL);
02989   }
02990 
02991 end:
02992 
02993   /* Show warnings if any or error occured */
02994   if (show_warnings == 1 && (warnings >= 1 || error))
02995     print_warnings(error_code);
02996 
02997   if (!error && !status.getBatch() and
02998       drizzle_con_status(con) & DRIZZLE_CON_STATUS_DB_DROPPED)
02999   {
03000     get_current_db();
03001   }
03002 
03003   executing_query= false;
03004   return error;        /* New command follows */
03005 }
03006 
03007 
03008 static void init_pager()
03009 {
03010   if (opt_nopager == false)
03011   {
03012     if (!(PAGER= popen(pager.c_str(), "w")))
03013     {
03014       tee_fprintf(stdout,_( "popen() failed! defaulting PAGER to stdout!\n"));
03015       PAGER= stdout;
03016     }
03017   }
03018   else
03019   {
03020     PAGER= stdout;
03021   }
03022 }
03023 
03024 static void end_pager()
03025 {
03026   if (!opt_nopager)
03027     pclose(PAGER);
03028 }
03029 
03030 
03031 static void init_tee(const char *file_name)
03032 {
03033   FILE* new_outfile;
03034   if (opt_outfile)
03035   {
03036     end_tee();
03037   }
03038 
03039   if ((new_outfile= fopen(file_name, "a")) == NULL)
03040   {
03041     tee_fprintf(stdout, _("Error logging to file '%s'\n"), file_name);
03042     return;
03043   }
03044   OUTFILE = new_outfile;
03045   outfile= file_name;
03046   tee_fprintf(stdout, _("Logging to file '%s'\n"), file_name);
03047   opt_outfile= 1;
03048 
03049   return;
03050 }
03051 
03052 
03053 static void end_tee()
03054 {
03055   fclose(OUTFILE);
03056   OUTFILE= 0;
03057   opt_outfile= 0;
03058   return;
03059 }
03060 
03061 
03062 static int
03063 com_ego(string *buffer,const char *line)
03064 {
03065   int result;
03066   bool oldvertical=vertical;
03067   vertical=1;
03068   result=com_go(buffer,line);
03069   vertical=oldvertical;
03070   return result;
03071 }
03072 
03073 
03074 static const char *fieldtype2str(drizzle_column_type_t type)
03075 {
03076   switch (type) {
03077     case DRIZZLE_COLUMN_TYPE_BLOB:        return "BLOB";
03078     case DRIZZLE_COLUMN_TYPE_DATE:        return "DATE";
03079     case DRIZZLE_COLUMN_TYPE_DATETIME:    return "DATETIME";
03080     case DRIZZLE_COLUMN_TYPE_NEWDECIMAL:  return "DECIMAL";
03081     case DRIZZLE_COLUMN_TYPE_DOUBLE:      return "DOUBLE";
03082     case DRIZZLE_COLUMN_TYPE_ENUM:        return "ENUM";
03083     case DRIZZLE_COLUMN_TYPE_LONG:        return "LONG";
03084     case DRIZZLE_COLUMN_TYPE_LONGLONG:    return "LONGLONG";
03085     case DRIZZLE_COLUMN_TYPE_NULL:        return "NULL";
03086     case DRIZZLE_COLUMN_TYPE_TIMESTAMP:   return "TIMESTAMP";
03087     default:                     return "?-unknown-?";
03088   }
03089 }
03090 
03091 static char *fieldflags2str(uint32_t f) {
03092   static char buf[1024];
03093   char *s=buf;
03094   *s=0;
03095 #define ff2s_check_flag(X)                                              \
03096   if (f & DRIZZLE_COLUMN_FLAGS_ ## X) { s=strcpy(s, # X " ")+strlen(# X " "); \
03097                         f &= ~ DRIZZLE_COLUMN_FLAGS_ ## X; }
03098   ff2s_check_flag(NOT_NULL);
03099   ff2s_check_flag(PRI_KEY);
03100   ff2s_check_flag(UNIQUE_KEY);
03101   ff2s_check_flag(MULTIPLE_KEY);
03102   ff2s_check_flag(BLOB);
03103   ff2s_check_flag(UNSIGNED);
03104   ff2s_check_flag(BINARY);
03105   ff2s_check_flag(ENUM);
03106   ff2s_check_flag(AUTO_INCREMENT);
03107   ff2s_check_flag(TIMESTAMP);
03108   ff2s_check_flag(SET);
03109   ff2s_check_flag(NO_DEFAULT_VALUE);
03110   ff2s_check_flag(NUM);
03111   ff2s_check_flag(PART_KEY);
03112   ff2s_check_flag(GROUP);
03113   ff2s_check_flag(UNIQUE);
03114   ff2s_check_flag(BINCMP);
03115   ff2s_check_flag(ON_UPDATE_NOW);
03116 #undef ff2s_check_flag
03117   if (f)
03118     sprintf(s, " unknows=0x%04x", f);
03119   return buf;
03120 }
03121 
03122 static void
03123 print_field_types(drizzle_result_st *result)
03124 {
03125   drizzle_column_st   *field;
03126   uint32_t i=0;
03127 
03128   while ((field = drizzle_column_next(result)))
03129   {
03130     tee_fprintf(PAGER, _("Field %3u:  `%s`\n"
03131                 "Catalog:    `%s`\n"
03132                 "Schema:     `%s`\n"
03133                 "Table:      `%s`\n"
03134                 "Org_table:  `%s`\n"
03135                 "Type:       UTF-8\n"
03136                 "Collation:  %s (%u)\n"
03137                 "Length:     %lu\n"
03138                 "Max_length: %lu\n"
03139                 "Decimals:   %u\n"
03140                 "Flags:      %s\n\n"),
03141                 ++i,
03142                 drizzle_column_name(field), drizzle_column_catalog(field),
03143                 drizzle_column_db(field), drizzle_column_table(field),
03144                 drizzle_column_orig_table(field),
03145                 fieldtype2str(drizzle_column_type(field)),
03146                 drizzle_column_charset(field), drizzle_column_size(field),
03147                 drizzle_column_max_size(field), drizzle_column_decimals(field),
03148                 fieldflags2str(drizzle_column_flags(field)));
03149   }
03150   tee_puts("", PAGER);
03151 }
03152 
03153 static void
03154 print_table_data(drizzle_result_st *result)
03155 {
03156   drizzle_row_t cur;
03157   drizzle_return_t ret;
03158   drizzle_column_st *field;
03159   std::vector<bool> num_flag;
03160   std::vector<bool> boolean_flag;
03161   std::vector<bool> ansi_boolean_flag;
03162   string separator;
03163 
03164   separator.reserve(256);
03165 
03166   num_flag.resize(drizzle_result_column_count(result));
03167   boolean_flag.resize(drizzle_result_column_count(result));
03168   ansi_boolean_flag.resize(drizzle_result_column_count(result));
03169   if (column_types_flag)
03170   {
03171     print_field_types(result);
03172     if (!drizzle_result_row_count(result))
03173       return;
03174     drizzle_column_seek(result,0);
03175   }
03176   separator.append("+");
03177   while ((field = drizzle_column_next(result)))
03178   {
03179     uint32_t x, length= 0;
03180 
03181     if (column_names)
03182     {
03183       uint32_t name_length= strlen(drizzle_column_name(field));
03184 
03185       /* Check if the max_byte value is really the maximum in terms
03186          of visual length since multibyte characters can affect the
03187          length of the separator. */
03188       length= drizzled::utf8::char_length(drizzle_column_name(field));
03189 
03190       if (name_length == drizzle_column_max_size(field))
03191       {
03192         if (length < drizzle_column_max_size(field))
03193           drizzle_column_set_max_size(field, length);
03194       }
03195       else
03196       {
03197         length= name_length;
03198       }
03199     }
03200   
03201     if (quick)
03202       length=max(length,drizzle_column_size(field));
03203     else
03204       length=max(length,(uint32_t)drizzle_column_max_size(field));
03205     if (length < 4 &&
03206         !(drizzle_column_flags(field) & DRIZZLE_COLUMN_FLAGS_NOT_NULL))
03207     {
03208       // Room for "NULL"
03209       length=4;
03210     }
03211     if ((length < 5) and 
03212       (server_type == ServerDetect::SERVER_DRIZZLE_FOUND) and
03213       (drizzle_column_type(field) == DRIZZLE_COLUMN_TYPE_TINY) and
03214       (drizzle_column_type(field) & DRIZZLE_COLUMN_FLAGS_UNSIGNED))
03215     {
03216       // Room for "FALSE"
03217       length= 5;
03218     }
03219     drizzle_column_set_max_size(field, length);
03220 
03221     for (x=0; x< (length+2); x++)
03222       separator.append("-");
03223     separator.append("+");
03224   }
03225 
03226   tee_puts((char*) separator.c_str(), PAGER);
03227   if (column_names)
03228   {
03229     drizzle_column_seek(result,0);
03230     (void) tee_fputs("|", PAGER);
03231     for (uint32_t off=0; (field = drizzle_column_next(result)) ; off++)
03232     {
03233       uint32_t name_length= (uint32_t) strlen(drizzle_column_name(field));
03234       uint32_t numcells= drizzled::utf8::char_length(drizzle_column_name(field));
03235       uint32_t display_length= drizzle_column_max_size(field) + name_length -
03236                                numcells;
03237       tee_fprintf(PAGER, " %-*s |",(int) min(display_length,
03238                                              MAX_COLUMN_LENGTH),
03239                   drizzle_column_name(field));
03240       num_flag[off]= ((drizzle_column_type(field) <= DRIZZLE_COLUMN_TYPE_LONGLONG) ||
03241                       (drizzle_column_type(field) == DRIZZLE_COLUMN_TYPE_NEWDECIMAL));
03242       if ((server_type == ServerDetect::SERVER_DRIZZLE_FOUND) and
03243         (drizzle_column_type(field) == DRIZZLE_COLUMN_TYPE_TINY))
03244       {
03245         if ((drizzle_column_flags(field) & DRIZZLE_COLUMN_FLAGS_UNSIGNED))
03246         {
03247           ansi_boolean_flag[off]= true;
03248         }
03249         else
03250         {
03251           ansi_boolean_flag[off]= false;
03252         }
03253         boolean_flag[off]= true;
03254         num_flag[off]= false;
03255       }
03256       else
03257       {
03258         boolean_flag[off]= false;
03259       }
03260     }
03261     (void) tee_fputs("\n", PAGER);
03262     tee_puts((char*) separator.c_str(), PAGER);
03263   }
03264 
03265   while (1)
03266   {
03267     if (quick)
03268     {
03269       cur= drizzle_row_buffer(result, &ret);
03270       if (ret != DRIZZLE_RETURN_OK)
03271       {
03272         (void)put_error(con, result);
03273         break;
03274       }
03275     }
03276     else
03277       cur= drizzle_row_next(result);
03278 
03279     if (cur == NULL || interrupted_query)
03280       break;
03281 
03282     size_t *lengths= drizzle_row_field_sizes(result);
03283     (void) tee_fputs("| ", PAGER);
03284     drizzle_column_seek(result, 0);
03285     for (uint32_t off= 0; off < drizzle_result_column_count(result); off++)
03286     {
03287       const char *buffer;
03288       uint32_t data_length;
03289       uint32_t field_max_length;
03290       uint32_t visible_length;
03291       uint32_t extra_padding;
03292 
03293       if (cur[off] == NULL)
03294       {
03295         buffer= "NULL";
03296         data_length= 4;
03297       }
03298       else if (boolean_flag[off])
03299       {
03300         if (strncmp(cur[off],"1", 1) == 0)
03301         {
03302           if (ansi_boolean_flag[off])
03303           {
03304             buffer= "YES";
03305             data_length= 3;
03306           }
03307           else
03308           {
03309             buffer= "TRUE";
03310             data_length= 4;
03311           }
03312         }
03313         else
03314         {
03315           if (ansi_boolean_flag[off])
03316           {
03317             buffer= "NO";
03318             data_length= 2;
03319           }
03320           else
03321           {
03322             buffer= "FALSE";
03323             data_length= 5;
03324           }
03325         }
03326       }
03327       else
03328       {
03329         buffer= cur[off];
03330         data_length= (uint32_t) lengths[off];
03331       }
03332 
03333       field= drizzle_column_next(result);
03334       field_max_length= drizzle_column_max_size(field);
03335 
03336       /*
03337         How many text cells on the screen will this string span?  If it contains
03338         multibyte characters, then the number of characters we occupy on screen
03339         will be fewer than the number of bytes we occupy in memory.
03340 
03341         We need to find how much screen real-estate we will occupy to know how
03342         many extra padding-characters we should send with the printing function.
03343       */
03344       visible_length= drizzled::utf8::char_length(buffer);
03345       extra_padding= data_length - visible_length;
03346 
03347       if (field_max_length > MAX_COLUMN_LENGTH)
03348         tee_print_sized_data(buffer, data_length, MAX_COLUMN_LENGTH+extra_padding, false);
03349       else
03350       {
03351         if (num_flag[off] != 0) /* if it is numeric, we right-justify it */
03352           tee_print_sized_data(buffer, data_length, field_max_length+extra_padding, true);
03353         else
03354           tee_print_sized_data(buffer, data_length,
03355                                field_max_length+extra_padding, false);
03356       }
03357       tee_fputs(" | ", PAGER);
03358     }
03359     (void) tee_fputs("\n", PAGER);
03360     if (quick)
03361       drizzle_row_free(result, cur);
03362   }
03363   tee_puts(separator.c_str(), PAGER);
03364 }
03365 
03382 static int get_field_disp_length(drizzle_column_st *field)
03383 {
03384   uint32_t length= column_names ? strlen(drizzle_column_name(field)) : 0;
03385 
03386   if (quick)
03387     length= max(length, drizzle_column_size(field));
03388   else
03389     length= max(length, (uint32_t)drizzle_column_max_size(field));
03390 
03391   if (length < 4 &&
03392     !(drizzle_column_flags(field) & DRIZZLE_COLUMN_FLAGS_NOT_NULL))
03393   {
03394     length= 4;        /* Room for "NULL" */
03395   }
03396 
03397   return length;
03398 }
03399 
03408 static int get_result_width(drizzle_result_st *result)
03409 {
03410   unsigned int len= 0;
03411   drizzle_column_st *field;
03412   uint16_t offset;
03413 
03414   offset= drizzle_column_current(result);
03415   assert(offset == 0);
03416 
03417   while ((field= drizzle_column_next(result)) != NULL)
03418     len+= get_field_disp_length(field) + 3; /* plus bar, space, & final space */
03419 
03420   (void) drizzle_column_seek(result, offset);
03421 
03422   return len + 1; /* plus final bar. */
03423 }
03424 
03425 static void
03426 tee_print_sized_data(const char *data, unsigned int data_length, unsigned int total_bytes_to_send, bool right_justified)
03427 {
03428   /*
03429     For '\0's print ASCII spaces instead, as '\0' is eaten by (at
03430     least my) console driver, and that messes up the pretty table
03431     grid.  (The \0 is also the reason we can't use fprintf() .)
03432   */
03433   unsigned int i;
03434   const char *p;
03435 
03436   if (right_justified)
03437     for (i= data_length; i < total_bytes_to_send; i++)
03438       tee_putc((int)' ', PAGER);
03439 
03440   for (i= 0, p= data; i < data_length; i+= 1, p+= 1)
03441   {
03442     if (*p == '\0')
03443       tee_putc((int)' ', PAGER);
03444     else
03445       tee_putc((int)*p, PAGER);
03446   }
03447 
03448   if (! right_justified)
03449     for (i= data_length; i < total_bytes_to_send; i++)
03450       tee_putc((int)' ', PAGER);
03451 }
03452 
03453 
03454 
03455 static void
03456 print_table_data_vertically(drizzle_result_st *result)
03457 {
03458   drizzle_row_t cur;
03459   drizzle_return_t ret;
03460   uint32_t max_length=0;
03461   drizzle_column_st *field;
03462 
03463   while ((field = drizzle_column_next(result)))
03464   {
03465     uint32_t length= strlen(drizzle_column_name(field));
03466     if (length > max_length)
03467       max_length= length;
03468     drizzle_column_set_max_size(field, length);
03469   }
03470 
03471   for (uint32_t row_count=1;; row_count++)
03472   {
03473     if (quick)
03474     {
03475       cur= drizzle_row_buffer(result, &ret);
03476       if (ret != DRIZZLE_RETURN_OK)
03477       {
03478         (void)put_error(con, result);
03479         break;
03480       }
03481     }
03482     else
03483       cur= drizzle_row_next(result);
03484 
03485     if (cur == NULL || interrupted_query)
03486       break;
03487     drizzle_column_seek(result,0);
03488     tee_fprintf(PAGER,
03489                 "*************************** %d. row ***************************\n", row_count);
03490     for (uint32_t off=0; off < drizzle_result_column_count(result); off++)
03491     {
03492       field= drizzle_column_next(result);
03493       tee_fprintf(PAGER, "%*s: ",(int) max_length,drizzle_column_name(field));
03494       tee_fprintf(PAGER, "%s\n",cur[off] ? (char*) cur[off] : "NULL");
03495     }
03496     if (quick)
03497       drizzle_row_free(result, cur);
03498   }
03499 }
03500 
03501 
03502 /* print_warnings should be called right after executing a statement */
03503 
03504 static void print_warnings(uint32_t error_code)
03505 {
03506   const char *query;
03507   drizzle_result_st result;
03508   drizzle_row_t cur;
03509   uint64_t num_rows;
03510   uint32_t new_code= 0;
03511   FILE *out;
03512 
03513   /* Get the warnings */
03514   query= "show warnings";
03515   drizzleclient_real_query_for_lazy(query, strlen(query),&result,&new_code);
03516   drizzleclient_store_result_for_lazy(&result);
03517 
03518   /* Bail out when no warnings */
03519   if (!(num_rows= drizzle_result_row_count(&result)))
03520     goto end;
03521 
03522   cur= drizzle_row_next(&result);
03523 
03524   /*
03525     Don't print a duplicate of the current error.  It is possible for SHOW
03526     WARNINGS to return multiple errors with the same code, but different
03527     messages.  To be safe, skip printing the duplicate only if it is the only
03528     warning.
03529   */
03530   if (!cur || (num_rows == 1 &&
03531       error_code == (uint32_t) strtoul(cur[1], NULL, 10)))
03532   {
03533     goto end;
03534   }
03535 
03536   /* Print the warnings */
03537   if (status.getBatch()) 
03538   {
03539     out= stderr;
03540   } 
03541   else 
03542   {
03543     init_pager();
03544     out= PAGER;
03545   }
03546   do
03547   {
03548     tee_fprintf(out, "%s (Code %s): %s\n", cur[0], cur[1], cur[2]);
03549   } while ((cur= drizzle_row_next(&result)));
03550 
03551   if (not status.getBatch())
03552     end_pager();
03553 
03554 end:
03555   drizzle_result_free(&result);
03556 }
03557 
03558 
03559 static void
03560 safe_put_field(const char *pos,uint32_t length)
03561 {
03562   if (!pos)
03563     tee_fputs("NULL", PAGER);
03564   else
03565   {
03566     if (opt_raw_data)
03567       tee_fputs(pos, PAGER);
03568     else for (const char *end=pos+length ; pos != end ; pos++)
03569     {
03570       int l;
03571       if ((l = drizzled::utf8::sequence_length(*pos)))
03572       {
03573         while (l--)
03574           tee_putc(*pos++, PAGER);
03575         pos--;
03576         continue;
03577       }
03578       if (!*pos)
03579         tee_fputs("\\0", PAGER); // This makes everything hard
03580       else if (*pos == '\t')
03581         tee_fputs("\\t", PAGER); // This would destroy tab format
03582       else if (*pos == '\n')
03583         tee_fputs("\\n", PAGER); // This too
03584       else if (*pos == '\\')
03585         tee_fputs("\\\\", PAGER);
03586       else
03587         tee_putc(*pos, PAGER);
03588     }
03589   }
03590 }
03591 
03592 
03593 static void
03594 print_tab_data(drizzle_result_st *result)
03595 {
03596   drizzle_row_t cur;
03597   drizzle_return_t ret;
03598   drizzle_column_st *field;
03599   size_t *lengths;
03600   std::vector<bool> boolean_flag;
03601   std::vector<bool> ansi_boolean_flag;
03602 
03603   boolean_flag.resize(drizzle_result_column_count(result));
03604   ansi_boolean_flag.resize(drizzle_result_column_count(result));
03605 
03606   int first=0;
03607   for (uint32_t off= 0; (field = drizzle_column_next(result)); off++)
03608   {
03609     if (opt_silent < 2 && column_names)
03610     {
03611       if (first++)
03612         (void) tee_fputs("\t", PAGER);
03613       (void) tee_fputs(drizzle_column_name(field), PAGER);
03614     }
03615     if ((server_type == ServerDetect::SERVER_DRIZZLE_FOUND) and
03616       (drizzle_column_type(field) == DRIZZLE_COLUMN_TYPE_TINY))
03617     {
03618       if ((drizzle_column_flags(field) & DRIZZLE_COLUMN_FLAGS_UNSIGNED))
03619       {
03620         ansi_boolean_flag[off]= true;
03621       }
03622       else
03623       {
03624         ansi_boolean_flag[off]= false;
03625       }
03626       boolean_flag[off]= true;
03627     }
03628     else
03629     {
03630       boolean_flag[off]= false;
03631     }
03632   }
03633   if (opt_silent < 2 && column_names)
03634   {
03635     (void) tee_fputs("\n", PAGER);
03636   }
03637   while (1)
03638   {
03639     if (quick)
03640     {
03641       cur= drizzle_row_buffer(result, &ret);
03642       if (ret != DRIZZLE_RETURN_OK)
03643       {
03644         (void)put_error(con, result);
03645         break;
03646       }
03647     }
03648     else
03649       cur= drizzle_row_next(result);
03650 
03651     if (cur == NULL)
03652       break;
03653 
03654     lengths= drizzle_row_field_sizes(result);
03655     drizzle_column_seek(result, 0);
03656     for (uint32_t off=0 ; off < drizzle_result_column_count(result); off++)
03657     {
03658       if (off != 0)
03659         (void) tee_fputs("\t", PAGER);
03660       if (boolean_flag[off])
03661       {
03662         if (strncmp(cur[off],"1", 1) == 0)
03663         {
03664           if (ansi_boolean_flag[off])
03665           {
03666             safe_put_field("YES", 3);
03667           }
03668           else
03669           {
03670             safe_put_field("TRUE", 4);
03671           }
03672         }
03673         else
03674         {
03675           if (ansi_boolean_flag[off])
03676           {
03677             safe_put_field("NO", 2);
03678           }
03679           else
03680           {
03681             safe_put_field("FALSE", 5);
03682           }
03683         }
03684       }
03685       else
03686       {
03687         safe_put_field(cur[off], lengths[off]);
03688       }
03689     }
03690     (void) tee_fputs("\n", PAGER);
03691     if (quick)
03692       drizzle_row_free(result, cur);
03693   }
03694 }
03695 
03696 static int
03697 com_tee(string *, const char *line )
03698 {
03699   char file_name[FN_REFLEN], *end;
03700   const char *param;
03701 
03702   if (status.getBatch())
03703     return 0;
03704   while (isspace(*line))
03705     line++;
03706   if (!(param =strchr(line, ' '))) // if outfile wasn't given, use the default
03707   {
03708     if (outfile.empty())
03709     {
03710       printf(_("No previous outfile available, you must give a filename!\n"));
03711       return 0;
03712     }
03713     else if (opt_outfile)
03714     {
03715       tee_fprintf(stdout, _("Currently logging to file '%s'\n"), outfile.c_str());
03716       return 0;
03717     }
03718     else
03719       param= outfile.c_str();      //resume using the old outfile
03720   }
03721 
03722   /* @TODO: Replace this with string methods */
03723   /* eliminate the spaces before the parameters */
03724   while (isspace(*param))
03725     param++;
03726   strncpy(file_name, param, sizeof(file_name) - 1);
03727   end= file_name + strlen(file_name);
03728   /* remove end space from command line */
03729   while (end > file_name && (isspace(end[-1]) ||
03730                              iscntrl(end[-1])))
03731     end--;
03732   end[0]= 0;
03733   if (end == file_name)
03734   {
03735     printf(_("No outfile specified!\n"));
03736     return 0;
03737   }
03738   init_tee(file_name);
03739   return 0;
03740 }
03741 
03742 
03743 static int
03744 com_notee(string *, const char *)
03745 {
03746   if (opt_outfile)
03747     end_tee();
03748   tee_fprintf(stdout, _("Outfile disabled.\n"));
03749   return 0;
03750 }
03751 
03752 /*
03753   Sorry, this command is not available in Windows.
03754 */
03755 
03756 static int
03757 com_pager(string *, const char *line)
03758 {
03759   const char *param;
03760 
03761   if (status.getBatch())
03762     return 0;
03763   /* Skip spaces in front of the pager command */
03764   while (isspace(*line))
03765     line++;
03766   /* Skip the pager command */
03767   param= strchr(line, ' ');
03768   /* Skip the spaces between the command and the argument */
03769   while (param && isspace(*param))
03770     param++;
03771   if (!param || (*param == '\0')) // if pager was not given, use the default
03772   {
03773     if (!default_pager_set)
03774     {
03775       tee_fprintf(stdout, _("Default pager wasn't set, using stdout.\n"));
03776       opt_nopager=1;
03777       pager= "stdout";
03778       PAGER= stdout;
03779       return 0;
03780     }
03781     pager= default_pager;
03782   }
03783   else
03784   {
03785     string pager_name(param);
03786     string::iterator end= pager_name.end();
03787     while (end > pager_name.begin() &&
03788            (isspace(*(end-1)) || iscntrl(*(end-1))))
03789       --end;
03790     pager_name.erase(end, pager_name.end());
03791     pager= pager_name;
03792     default_pager= pager_name;
03793   }
03794   opt_nopager=0;
03795   tee_fprintf(stdout, _("PAGER set to '%s'\n"), pager.c_str());
03796   return 0;
03797 }
03798 
03799 
03800 static int
03801 com_nopager(string *, const char *)
03802 {
03803   pager= "stdout";
03804   opt_nopager=1;
03805   PAGER= stdout;
03806   tee_fprintf(stdout, _("PAGER set to stdout\n"));
03807   return 0;
03808 }
03809 
03810 /* If arg is given, exit without errors. This happens on command 'quit' */
03811 
03812 static int
03813 com_quit(string *, const char *)
03814 {
03815   /* let the screen auto close on a normal shutdown */
03816   status.setExitStatus(0);
03817   return 1;
03818 }
03819 
03820 static int
03821 com_rehash(string *, const char *)
03822 {
03823   build_completion_hash(1, 0);
03824   return 0;
03825 }
03826 
03827 
03828 
03829 static int
03830 com_print(string *buffer,const char *)
03831 {
03832   tee_puts("--------------", stdout);
03833   (void) tee_fputs(buffer->c_str(), stdout);
03834   if ( (buffer->length() == 0)
03835        || (buffer->c_str())[(buffer->length())-1] != '\n')
03836     tee_putc('\n', stdout);
03837   tee_puts("--------------\n", stdout);
03838   /* If empty buffer */
03839   return 0;
03840 }
03841 
03842 /* ARGSUSED */
03843 static int
03844 com_connect(string *buffer, const char *line)
03845 {
03846   char *tmp, buff[256];
03847   bool save_rehash= opt_rehash;
03848   int error;
03849 
03850   memset(buff, 0, sizeof(buff));
03851   if (buffer)
03852   {
03853     /*
03854       Two null bytes are needed in the end of buff to allow
03855       get_arg to find end of string the second time it's called.
03856     */
03857     tmp= strncpy(buff, line, sizeof(buff)-2);
03858 #ifdef EXTRA_DEBUG
03859     tmp[1]= 0;
03860 #endif
03861     tmp= get_arg(buff, 0);
03862     if (tmp && *tmp)
03863     {
03864       current_db= tmp;
03865       tmp= get_arg(buff, 1);
03866       if (tmp)
03867       {
03868         current_host.erase();
03869         current_host=strdup(tmp);
03870       }
03871     }
03872     else
03873     {
03874       /* Quick re-connect */
03875       opt_rehash= 0;
03876     }
03877     // command used
03878     assert(buffer!=NULL);
03879     buffer->clear();
03880   }
03881   else
03882     opt_rehash= 0;
03883   error=sql_connect(current_host, current_db, current_user, opt_password);
03884   opt_rehash= save_rehash;
03885 
03886   if (connected)
03887   {
03888     sprintf(buff, _("Connection id:    %u"), drizzle_con_thread_id(con));
03889     put_info(buff,INFO_INFO,0,0);
03890     sprintf(buff, _("Current schema: %.128s\n"),
03891             !current_db.empty() ? current_db.c_str() : _("*** NONE ***"));
03892     put_info(buff,INFO_INFO,0,0);
03893   }
03894   return error;
03895 }
03896 
03897 
03898 static int com_source(string *, const char *line)
03899 {
03900   char source_name[FN_REFLEN], *end;
03901   const char *param;
03902   LineBuffer *line_buff;
03903   int error;
03904   Status old_status;
03905   FILE *sql_file;
03906 
03907   /* Skip space from file name */
03908   while (isspace(*line))
03909     line++;
03910   if (!(param = strchr(line, ' ')))    // Skip command name
03911     return put_info(_("Usage: \\. <filename> | source <filename>"),
03912                     INFO_ERROR, 0,0);
03913   while (isspace(*param))
03914     param++;
03915   end= strncpy(source_name,param,sizeof(source_name)-1);
03916   end+= strlen(source_name);
03917   while (end > source_name && (isspace(end[-1]) ||
03918                                iscntrl(end[-1])))
03919     end--;
03920   end[0]=0;
03921 
03922   /* open file name */
03923   if (!(sql_file = fopen(source_name, "r")))
03924   {
03925     char buff[FN_REFLEN+60];
03926     sprintf(buff, _("Failed to open file '%s', error: %d"), source_name,errno);
03927     return put_info(buff, INFO_ERROR, 0 ,0);
03928   }
03929 
03930   line_buff= new LineBuffer(opt_max_input_line,sql_file);
03931 
03932   /* Save old status */
03933   old_status=status;
03934   memset(&status, 0, sizeof(status));
03935 
03936   // Run in batch mode
03937   status.setBatch(old_status.getBatch());
03938   status.setLineBuff(line_buff);
03939   status.setFileName(source_name);
03940   // Empty command buffer
03941   assert(glob_buffer!=NULL);
03942   glob_buffer->clear();
03943   error= read_and_execute(false);
03944   // Continue as before
03945   status=old_status;
03946   fclose(sql_file);
03947   delete status.getLineBuff();
03948   line_buff=0;
03949   status.setLineBuff(0);
03950   return error;
03951 }
03952 
03953 
03954 /* ARGSUSED */
03955 static int
03956 com_delimiter(string *, const char *line)
03957 {
03958   char buff[256];
03959 
03960   strncpy(buff, line, sizeof(buff) - 1);
03961   char* tmp= get_arg(buff, 0);
03962 
03963   if (!tmp || !*tmp)
03964   {
03965     put_info(_("DELIMITER must be followed by a 'delimiter' character or string"), INFO_ERROR, 0, 0);
03966     return 0;
03967   }
03968   else
03969   {
03970     if (strstr(tmp, "\\"))
03971     {
03972       put_info(_("DELIMITER cannot contain a backslash character"), INFO_ERROR, 0, 0);
03973       return 0;
03974     }
03975   }
03976   delimiter= strdup(tmp);
03977   delimiter_length= (int)strlen(delimiter);
03978   delimiter_str= delimiter;
03979   return 0;
03980 }
03981 
03982 /* ARGSUSED */
03983 static int
03984 com_use(string *, const char *line)
03985 {
03986   char *tmp, buff[FN_REFLEN + 1];
03987   int select_db;
03988   drizzle_result_st result;
03989   drizzle_return_t ret;
03990 
03991   memset(buff, 0, sizeof(buff));
03992   strncpy(buff, line, sizeof(buff) - 1);
03993   tmp= get_arg(buff, 0);
03994   if (!tmp || !*tmp)
03995   {
03996     put_info(_("USE must be followed by a schema name"), INFO_ERROR, 0, 0);
03997     return 0;
03998   }
03999   /*
04000     We need to recheck the current database, because it may change
04001     under our feet, for example if DROP DATABASE or RENAME DATABASE
04002     (latter one not yet available by the time the comment was written)
04003   */
04004   get_current_db();
04005 
04006   if (current_db.empty() || strcmp(current_db.c_str(),tmp))
04007   {
04008     if (one_database)
04009     {
04010       skip_updates= 1;
04011       select_db= 0;    // don't do drizzleclient_select_db()
04012     }
04013     else
04014       select_db= 2;    // do drizzleclient_select_db() and build_completion_hash()
04015   }
04016   else
04017   {
04018     /*
04019       USE to the current db specified.
04020       We do need to send drizzleclient_select_db() to make server
04021       update database level privileges, which might
04022       change since last USE (see bug#10979).
04023       For performance purposes, we'll skip rebuilding of completion hash.
04024     */
04025     skip_updates= 0;
04026     select_db= 1;      // do only drizzleclient_select_db(), without completion
04027   }
04028 
04029   if (select_db)
04030   {
04031     /*
04032       reconnect once if connection is down or if connection was found to
04033       be down during query
04034     */
04035     if (!connected && reconnect())
04036       return opt_reconnect ? -1 : 1;                        // Fatal error
04037     for (bool try_again= true; try_again; try_again= false)
04038     {
04039       if (drizzle_select_db(con, &result, tmp, &ret) == NULL ||
04040           ret != DRIZZLE_RETURN_OK)
04041       {
04042         if (ret == DRIZZLE_RETURN_ERROR_CODE)
04043         {
04044           int error= put_error(con, &result);
04045           drizzle_result_free(&result);
04046           return error;
04047         }
04048 
04049         if (ret != DRIZZLE_RETURN_LOST_CONNECTION || !try_again)
04050         {
04051           return put_error(con, NULL);
04052         }
04053 
04054         if (reconnect())
04055         {
04056           return opt_reconnect ? -1 : 1;                      // Fatal error
04057         }
04058       }
04059       else
04060         drizzle_result_free(&result);
04061     }
04062     current_db= tmp;
04063     if (select_db > 1)
04064       build_completion_hash(opt_rehash, 1);
04065   }
04066 
04067   put_info(_("Schema changed"),INFO_INFO, 0, 0);
04068   return 0;
04069 }
04070 
04071 static int com_shutdown(string *, const char *)
04072 {
04073   drizzle_result_st result;
04074   drizzle_return_t ret;
04075 
04076   if (verbose)
04077   {
04078     printf(_("shutting down drizzled"));
04079     if (opt_drizzle_port > 0)
04080       printf(_(" on port %d"), opt_drizzle_port);
04081     printf("... ");
04082   }
04083 
04084   if (drizzle_shutdown(con, &result, DRIZZLE_SHUTDOWN_DEFAULT,
04085                        &ret) == NULL || ret != DRIZZLE_RETURN_OK)
04086   {
04087     if (ret == DRIZZLE_RETURN_ERROR_CODE)
04088     {
04089       fprintf(stderr, _("shutdown failed; error: '%s'"), drizzle_result_error(&result));
04090       drizzle_result_free(&result);
04091     }
04092     else
04093     {
04094       fprintf(stderr, _("shutdown failed; error: '%s'"), drizzle_con_error(con));
04095     }
04096     return false;
04097   }
04098 
04099   drizzle_result_free(&result);
04100 
04101   if (verbose)
04102     printf(_("done\n"));
04103 
04104   return false;
04105 }
04106 
04107 static int
04108 com_warnings(string *, const char *)
04109 {
04110   show_warnings = 1;
04111   put_info(_("Show warnings enabled."),INFO_INFO, 0, 0);
04112   return 0;
04113 }
04114 
04115 static int
04116 com_nowarnings(string *, const char *)
04117 {
04118   show_warnings = 0;
04119   put_info(_("Show warnings disabled."),INFO_INFO, 0, 0);
04120   return 0;
04121 }
04122 
04123 /*
04124   Gets argument from a command on the command line. If get_next_arg is
04125   not defined, skips the command and returns the first argument. The
04126   line is modified by adding zero to the end of the argument. If
04127   get_next_arg is defined, then the function searches for end of string
04128   first, after found, returns the next argument and adds zero to the
04129   end. If you ever wish to use this feature, remember to initialize all
04130   items in the array to zero first.
04131 */
04132 
04133 char *get_arg(char *line, bool get_next_arg)
04134 {
04135   char *ptr, *start;
04136   bool quoted= 0, valid_arg= 0;
04137   char qtype= 0;
04138 
04139   ptr= line;
04140   if (get_next_arg)
04141   {
04142     for (; *ptr; ptr++) ;
04143     if (*(ptr + 1))
04144       ptr++;
04145   }
04146   else
04147   {
04148     /* skip leading white spaces */
04149     while (isspace(*ptr))
04150       ptr++;
04151     if (*ptr == '\\') // short command was used
04152       ptr+= 2;
04153     else
04154       while (*ptr &&!isspace(*ptr)) // skip command
04155         ptr++;
04156   }
04157   if (!*ptr)
04158     return NULL;
04159   while (isspace(*ptr))
04160     ptr++;
04161   if (*ptr == '\'' || *ptr == '\"' || *ptr == '`')
04162   {
04163     qtype= *ptr;
04164     quoted= 1;
04165     ptr++;
04166   }
04167   for (start=ptr ; *ptr; ptr++)
04168   {
04169     if (*ptr == '\\' && ptr[1]) // escaped character
04170     {
04171       // Remove the backslash
04172       strcpy(ptr, ptr+1);
04173     }
04174     else if ((!quoted && *ptr == ' ') || (quoted && *ptr == qtype))
04175     {
04176       *ptr= 0;
04177       break;
04178     }
04179   }
04180   valid_arg= ptr != start;
04181   return valid_arg ? start : NULL;
04182 }
04183 
04184 
04185 static int
04186 sql_connect(const string &host, const string &database, const string &user, const string &password)
04187 {
04188   drizzle_return_t ret;
04189   if (connected)
04190   {
04191     connected= 0;
04192     drizzle_con_free(con);
04193     drizzle_free(drizzle);
04194   }
04195 
04196   drizzle= drizzle_create();
04197   if (drizzle == NULL)
04198   {
04199     return 1;
04200   }
04201 
04202   if ((con= drizzle_con_add_tcp(drizzle, host.c_str(),
04203                                 opt_drizzle_port, user.c_str(),
04204                                 password.c_str(), database.c_str(),
04205                                 global_con_options)) == NULL)
04206   {
04207     (void) put_error(con, NULL);
04208     (void) fflush(stdout);
04209     return 1;
04210   }
04211 
04212   if ((ret= drizzle_con_connect(con)) != DRIZZLE_RETURN_OK)
04213   {
04214 
04215     if (opt_silent < 2)
04216     {
04217       (void) put_error(con, NULL);
04218       (void) fflush(stdout);
04219       return ignore_errors ? -1 : 1;    // Abort
04220     }
04221     return -1;          // Retryable
04222   }
04223   connected= 1;
04224 
04225   ServerDetect server_detect(con);
04226   server_type= server_detect.getServerType();
04227 
04228   build_completion_hash(opt_rehash, 1);
04229   return 0;
04230 }
04231 
04232 
04233 static int
04234 com_status(string *, const char *)
04235 {
04236 /*
04237   char buff[40];
04238   uint64_t id;
04239 */
04240   drizzle_result_st result;
04241   drizzle_return_t ret;
04242 
04243   tee_puts("--------------", stdout);
04244   printf(_("Drizzle client %s build %s, for %s-%s (%s) using readline %s\n"),
04245          drizzle_version(), VERSION,
04246          HOST_VENDOR, HOST_OS, HOST_CPU,
04247          rl_library_version);
04248 
04249   if (connected)
04250   {
04251     tee_fprintf(stdout, _("\nConnection id:\t\t%lu\n"),drizzle_con_thread_id(con));
04252     /*
04253       Don't remove "limit 1",
04254       it is protection againts SQL_SELECT_LIMIT=0
04255     */
04256     if (drizzle_query_str(con, &result, "select DATABASE(), USER() limit 1",
04257                           &ret) != NULL && ret == DRIZZLE_RETURN_OK &&
04258         drizzle_result_buffer(&result) == DRIZZLE_RETURN_OK)
04259     {
04260       drizzle_row_t cur=drizzle_row_next(&result);
04261       if (cur)
04262       {
04263         tee_fprintf(stdout, _("Current schema:\t%s\n"), cur[0] ? cur[0] : "");
04264         tee_fprintf(stdout, _("Current user:\t\t%s\n"), cur[1]);
04265       }
04266       drizzle_result_free(&result);
04267     }
04268     else if (ret == DRIZZLE_RETURN_ERROR_CODE)
04269       drizzle_result_free(&result);
04270     tee_puts(_("SSL:\t\t\tNot in use"), stdout);
04271   }
04272   else
04273   {
04274     vidattr(A_BOLD);
04275     tee_fprintf(stdout, _("\nNo connection\n"));
04276     vidattr(A_NORMAL);
04277     return 0;
04278   }
04279   if (skip_updates)
04280   {
04281     vidattr(A_BOLD);
04282     tee_fprintf(stdout, _("\nAll updates ignored to this schema\n"));
04283     vidattr(A_NORMAL);
04284   }
04285   tee_fprintf(stdout, _("Current pager:\t\t%s\n"), pager.c_str());
04286   tee_fprintf(stdout, _("Using outfile:\t\t'%s'\n"), opt_outfile ? outfile.c_str() : "");
04287   tee_fprintf(stdout, _("Using delimiter:\t%s\n"), delimiter);
04288   tee_fprintf(stdout, _("Server version:\t\t%s\n"), server_version_string(con));
04289   tee_fprintf(stdout, _("Protocol:\t\t%s\n"), opt_protocol.c_str());
04290   tee_fprintf(stdout, _("Protocol version:\t%d\n"), drizzle_con_protocol_version(con));
04291   tee_fprintf(stdout, _("Connection:\t\t%s\n"), drizzle_con_host(con));
04292 /* XXX need to save this from result
04293   if ((id= drizzleclient_insert_id(&drizzle)))
04294     tee_fprintf(stdout, "Insert id:\t\t%s\n", internal::llstr(id, buff));
04295 */
04296 
04297   if (drizzle_con_uds(con))
04298   {
04299     tee_fprintf(stdout, _("UNIX socket:\t\t%s\n"), drizzle_con_uds(con));
04300   }
04301   else
04302   {
04303     tee_fprintf(stdout, _("TCP port:\t\t%d\n"), drizzle_con_port(con));
04304   }
04305 
04306   if (safe_updates)
04307   {
04308     vidattr(A_BOLD);
04309     tee_fprintf(stdout, _("\nNote that you are running in safe_update_mode:\n"));
04310     vidattr(A_NORMAL);
04311     tee_fprintf(stdout, _("\
04312 UPDATEs and DELETEs that don't use a key in the WHERE clause are not allowed.\n\
04313 (One can force an UPDATE/DELETE by adding LIMIT # at the end of the command.)\n \
04314 SELECT has an automatic 'LIMIT %lu' if LIMIT is not used.\n             \
04315 Max number of examined row combination in a join is set to: %lu\n\n"),
04316                 select_limit, max_join_size);
04317   }
04318   tee_puts("--------------\n", stdout);
04319   return 0;
04320 }
04321 
04322 static const char *
04323 server_version_string(drizzle_con_st *local_con)
04324 {
04325   static string buf("");
04326   static bool server_version_string_reserved= false;
04327 
04328   if (!server_version_string_reserved)
04329   {
04330     buf.reserve(MAX_SERVER_VERSION_LENGTH);
04331     server_version_string_reserved= true;
04332   }
04333   /* Only one thread calls this, so no synchronization is needed */
04334   if (buf[0] == '\0')
04335   {
04336     drizzle_result_st result;
04337     drizzle_return_t ret;
04338 
04339     buf.append(drizzle_con_server_version(local_con));
04340 
04341     /* "limit 1" is protection against SQL_SELECT_LIMIT=0 */
04342     (void)drizzle_query_str(local_con, &result,
04343                             "select @@version_comment limit 1", &ret);
04344     if (ret == DRIZZLE_RETURN_OK &&
04345         drizzle_result_buffer(&result) == DRIZZLE_RETURN_OK)
04346     {
04347       drizzle_row_t cur = drizzle_row_next(&result);
04348       if (cur && cur[0])
04349       {
04350         buf.append(" ");
04351         buf.append(cur[0]);
04352       }
04353       drizzle_result_free(&result);
04354     }
04355     else if (ret == DRIZZLE_RETURN_ERROR_CODE)
04356       drizzle_result_free(&result);
04357   }
04358 
04359   return buf.c_str();
04360 }
04361 
04362 static int
04363 put_info(const char *str,INFO_TYPE info_type, uint32_t error, const char *sqlstate)
04364 {
04365   FILE *file= (info_type == INFO_ERROR ? stderr : stdout);
04366   static int inited=0;
04367 
04368   if (status.getBatch())
04369   {
04370     if (info_type == INFO_ERROR)
04371     {
04372       (void) fflush(file);
04373       fprintf(file,_("ERROR"));
04374       if (error)
04375       {
04376         if (sqlstate)
04377           (void) fprintf(file," %d (%s)",error, sqlstate);
04378         else
04379           (void) fprintf(file," %d",error);
04380       }
04381       if (status.getQueryStartLine() && line_numbers)
04382       {
04383         (void) fprintf(file," at line %"PRIu32,status.getQueryStartLine());
04384         if (status.getFileName())
04385           (void) fprintf(file," in file: '%s'", status.getFileName());
04386       }
04387       (void) fprintf(file,": %s\n",str);
04388       (void) fflush(file);
04389       if (!ignore_errors)
04390         return 1;
04391     }
04392     else if (info_type == INFO_RESULT && verbose > 1)
04393       tee_puts(str, file);
04394     if (unbuffered)
04395       fflush(file);
04396     return info_type == INFO_ERROR ? -1 : 0;
04397   }
04398   if (!opt_silent || info_type == INFO_ERROR)
04399   {
04400     if (!inited)
04401     {
04402       inited=1;
04403 #ifdef HAVE_SETUPTERM
04404       (void) setupterm((char *)0, 1, (int *) 0);
04405 #endif
04406     }
04407     if (info_type == INFO_ERROR)
04408     {
04409       if (!opt_nobeep)
04410         /* This should make a bell */
04411         putchar('\a');
04412       vidattr(A_STANDOUT);
04413       if (error)
04414       {
04415         if (sqlstate)
04416           (void) tee_fprintf(file, _("ERROR %d (%s): "), error, sqlstate);
04417         else
04418           (void) tee_fprintf(file, _("ERROR %d: "), error);
04419       }
04420       else
04421         tee_puts(_("ERROR: "), file);
04422     }
04423     else
04424       vidattr(A_BOLD);
04425     (void) tee_puts(str, file);
04426     vidattr(A_NORMAL);
04427   }
04428   if (unbuffered)
04429     fflush(file);
04430   return info_type == INFO_ERROR ? -1 : 0;
04431 }
04432 
04433 
04434 static int
04435 put_error(drizzle_con_st *local_con, drizzle_result_st *res)
04436 {
04437   const char *error;
04438 
04439   if (res != NULL)
04440   {
04441     error= drizzle_result_error(res);
04442     if (!strcmp(error, ""))
04443     {
04444       error= drizzle_con_error(local_con);
04445     }
04446   }
04447   else
04448   {
04449     error= drizzle_con_error(local_con);
04450   }
04451 
04452   return put_info(error, INFO_ERROR,
04453                   res == NULL ? drizzle_con_error_code(local_con) :
04454                                 drizzle_result_error_code(res),
04455                   res == NULL ? drizzle_con_sqlstate(local_con) :
04456                                 drizzle_result_sqlstate(res));
04457 }
04458 
04459 
04460 static void remove_cntrl(string *buffer)
04461 {
04462   const char *start=  buffer->c_str();
04463   const char *end= start + (buffer->length());
04464   while (start < end && !isgraph(end[-1]))
04465     end--;
04466   uint32_t pos_to_truncate= (end-start);
04467   if (buffer->length() > pos_to_truncate)
04468     buffer->erase(pos_to_truncate);
04469 }
04470 
04471 
04472 void tee_fprintf(FILE *file, const char *fmt, ...)
04473 {
04474   va_list args;
04475 
04476   va_start(args, fmt);
04477   (void) vfprintf(file, fmt, args);
04478   va_end(args);
04479 
04480   if (opt_outfile)
04481   {
04482     va_start(args, fmt);
04483     (void) vfprintf(OUTFILE, fmt, args);
04484     va_end(args);
04485   }
04486 }
04487 
04488 
04489 void tee_fputs(const char *s, FILE *file)
04490 {
04491   fputs(s, file);
04492   if (opt_outfile)
04493     fputs(s, OUTFILE);
04494 }
04495 
04496 
04497 void tee_puts(const char *s, FILE *file)
04498 {
04499   fputs(s, file);
04500   fputc('\n', file);
04501   if (opt_outfile)
04502   {
04503     fputs(s, OUTFILE);
04504     fputc('\n', OUTFILE);
04505   }
04506 }
04507 
04508 void tee_putc(int c, FILE *file)
04509 {
04510   putc(c, file);
04511   if (opt_outfile)
04512     putc(c, OUTFILE);
04513 }
04514 
04515 #include <sys/times.h>
04516 
04517 static boost::posix_time::ptime start_timer(void)
04518 {
04519   return boost::posix_time::microsec_clock::universal_time();
04520 }
04521 
04522 static void nice_time(boost::posix_time::time_duration duration, string &buff)
04523 {
04524   ostringstream tmp_buff_str;
04525 
04526   if (duration.hours() > 0)
04527   {
04528     tmp_buff_str << duration.hours();
04529     if (duration.hours() > 1)
04530       tmp_buff_str << _(" hours ");
04531     else
04532       tmp_buff_str << _(" hour ");
04533   }
04534   if (duration.hours() > 0 || duration.minutes() > 0)
04535   {
04536     tmp_buff_str << duration.minutes() << _(" min ");
04537   }
04538 
04539   tmp_buff_str.precision(duration.num_fractional_digits());
04540 
04541   double seconds= duration.fractional_seconds();
04542 
04543   seconds/= pow(10.0,duration.num_fractional_digits());
04544 
04545   seconds+= duration.seconds();
04546   tmp_buff_str << seconds << _(" sec");
04547 
04548   buff.append(tmp_buff_str.str());
04549 }
04550 
04551 static void end_timer(boost::posix_time::ptime start_time, string &buff)
04552 {
04553   boost::posix_time::ptime end_time= start_timer();
04554   boost::posix_time::time_period duration(start_time, end_time);
04555 
04556   nice_time(duration.length(), buff);
04557 }
04558 
04559 
04560 static void drizzle_end_timer(boost::posix_time::ptime start_time, string &buff)
04561 {
04562   buff.append(" (");
04563   end_timer(start_time,buff);
04564   buff.append(")");
04565 }
04566 
04567 static const char * construct_prompt()
04568 {
04569   // Erase the old prompt
04570   assert(processed_prompt!=NULL);
04571   processed_prompt->clear();
04572 
04573   // Get the date struct
04574   time_t  lclock = time(NULL);
04575   struct tm *t = localtime(&lclock);
04576 
04577   /* parse thru the settings for the prompt */
04578   string::iterator c= current_prompt.begin();
04579   while (c != current_prompt.end())
04580   {
04581     if (*c != PROMPT_CHAR)
04582     {
04583       processed_prompt->push_back(*c);
04584     }
04585     else
04586     {
04587       int getHour;
04588       int getYear;
04589       /* Room for Dow MMM DD HH:MM:SS YYYY */ 
04590       char dateTime[32];
04591       switch (*++c) {
04592       case '\0':
04593         // stop it from going beyond if ends with %
04594         --c;
04595         break;
04596       case 'c':
04597         add_int_to_prompt(++prompt_counter);
04598         break;
04599       case 'v':
04600         if (connected)
04601           processed_prompt->append(drizzle_con_server_version(con));
04602         else
04603           processed_prompt->append("not_connected");
04604         break;
04605       case 'd':
04606         processed_prompt->append(not current_db.empty() ? current_db : "(none)");
04607         break;
04608       case 'h':
04609       {
04610         const char *prompt= connected ? drizzle_con_host(con) : "not_connected";
04611         if (strstr(prompt, "Localhost"))
04612           processed_prompt->append("localhost");
04613         else
04614         {
04615           const char *end=strrchr(prompt,' ');
04616           if (end != NULL)
04617             processed_prompt->append(prompt, (end-prompt));
04618         }
04619         break;
04620       }
04621       case 'p':
04622       {
04623         if (!connected)
04624         {
04625           processed_prompt->append("not_connected");
04626           break;
04627         }
04628 
04629         if (drizzle_con_uds(con))
04630         {
04631           const char *pos=strrchr(drizzle_con_uds(con),'/');
04632           processed_prompt->append(pos ? pos+1 : drizzle_con_uds(con));
04633         }
04634         else
04635           add_int_to_prompt(drizzle_con_port(con));
04636       }
04637       break;
04638       case 'U':
04639         if (!full_username)
04640           init_username();
04641         processed_prompt->append(full_username ? full_username :
04642                                  (!current_user.empty() ?  current_user : "(unknown)"));
04643         break;
04644       case 'u':
04645         if (!full_username)
04646           init_username();
04647         processed_prompt->append(part_username ? part_username :
04648                                  (!current_user.empty() ?  current_user : _("(unknown)")));
04649         break;
04650       case PROMPT_CHAR:
04651         {
04652           processed_prompt->append(PROMPT_CHAR, 1);
04653         }
04654         break;
04655       case 'n':
04656         {
04657           processed_prompt->append('\n', 1);
04658         }
04659         break;
04660       case ' ':
04661       case '_':
04662         {
04663           processed_prompt->append(' ', 1);
04664         }
04665         break;
04666       case 'R':
04667         if (t->tm_hour < 10)
04668           add_int_to_prompt(0);
04669         add_int_to_prompt(t->tm_hour);
04670         break;
04671       case 'r':
04672         getHour = t->tm_hour % 12;
04673         if (getHour == 0)
04674           getHour=12;
04675         if (getHour < 10)
04676           add_int_to_prompt(0);
04677         add_int_to_prompt(getHour);
04678         break;
04679       case 'm':
04680         if (t->tm_min < 10)
04681           add_int_to_prompt(0);
04682         add_int_to_prompt(t->tm_min);
04683         break;
04684       case 'y':
04685         getYear = t->tm_year % 100;
04686         if (getYear < 10)
04687           add_int_to_prompt(0);
04688         add_int_to_prompt(getYear);
04689         break;
04690       case 'Y':
04691         add_int_to_prompt(t->tm_year+1900);
04692         break;
04693       case 'D':
04694         strftime(dateTime, 32, "%a %b %d %H:%M:%S %Y", localtime(&lclock));
04695         processed_prompt->append(dateTime);
04696         break;
04697       case 's':
04698         if (t->tm_sec < 10)
04699           add_int_to_prompt(0);
04700         add_int_to_prompt(t->tm_sec);
04701         break;
04702       case 'w':
04703         processed_prompt->append(get_day_name(t->tm_wday));
04704         break;
04705       case 'P':
04706         processed_prompt->append(t->tm_hour < 12 ? "am" : "pm");
04707         break;
04708       case 'o':
04709         add_int_to_prompt(t->tm_mon+1);
04710         break;
04711       case 'O':
04712         processed_prompt->append(get_month_name(t->tm_mon));
04713         break;
04714       case '\'':
04715         processed_prompt->append("'");
04716         break;
04717       case '"':
04718         processed_prompt->append("\"");
04719         break;
04720       case 'S':
04721         processed_prompt->append(";");
04722         break;
04723       case 't':
04724         processed_prompt->append("\t");
04725         break;
04726       case 'l':
04727         processed_prompt->append(delimiter_str);
04728         break;
04729       default:
04730         processed_prompt->push_back(*c);
04731       }
04732     }
04733     ++c;
04734   }
04735   return processed_prompt->c_str();
04736 }
04737 
04738 
04739 static void add_int_to_prompt(int toadd)
04740 {
04741   ostringstream buffer;
04742   buffer << toadd;
04743   processed_prompt->append(buffer.str().c_str());
04744 }
04745 
04746 static void init_username()
04747 {
04748 /* XXX need this?
04749   free(full_username);
04750   free(part_username);
04751 
04752   drizzle_result_st *result;
04753   if (!drizzleclient_query(&drizzle,"select USER()") &&
04754       (result=drizzleclient_use_result(&drizzle)))
04755   {
04756     drizzle_row_t cur=drizzleclient_fetch_row(result);
04757     full_username= strdup(cur[0]);
04758     part_username= strdup(strtok(cur[0],"@"));
04759     (void) drizzleclient_fetch_row(result);        // Read eof
04760   }
04761 */
04762 }
04763 
04764 static int com_prompt(string *, const char *line)
04765 {
04766   const char *ptr=strchr(line, ' ');
04767   if (ptr == NULL)
04768     tee_fprintf(stdout, _("Returning to default PROMPT of %s\n"),
04769                 default_prompt);
04770   prompt_counter = 0;
04771   char * tmpptr= strdup(ptr ? ptr+1 : default_prompt);
04772   if (tmpptr == NULL)
04773     tee_fprintf(stdout, _("Memory allocation error. Not changing prompt\n"));
04774   else
04775   {
04776     current_prompt.erase();
04777     current_prompt= tmpptr;
04778     tee_fprintf(stdout, _("PROMPT set to '%s'\n"), current_prompt.c_str());
04779   }
04780   return 0;
04781 }
04782 
04783 /*
04784     strcont(str, set) if str contanies any character in the string set.
04785     The result is the position of the first found character in str, or NULL
04786     if there isn't anything found.
04787 */
04788 
04789 static const char * strcont(const char *str, const char *set)
04790 {
04791   const char * start = set;
04792 
04793   while (*str)
04794   {
04795     while (*set)
04796     {
04797       if (*set++ == *str)
04798         return str;
04799     }
04800     set=start; str++;
04801   }
04802   return NULL;
04803 } /* strcont */