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