1
/* Copyright (C) 2000-2008 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
1
/* - mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 MySQL
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16
21
/* mysql command tool
17
22
* Commands compatible with mSQL by David J. Hughes
193
198
static int get_options(int argc,char **argv);
194
199
extern "C" my_bool get_one_option(int optid, const struct my_option *opt,
196
static int com_quit(String *str,char*),
197
com_go(String *str,char*), com_ego(String *str,char*),
198
com_print(String *str,char*),
199
com_help(String *str,char*), com_clear(String *str,char*),
200
com_connect(String *str,char*), com_status(String *str,char*),
201
com_use(String *str,char*), com_source(String *str, char*),
202
com_rehash(String *str, char*), com_tee(String *str, char*),
203
com_notee(String *str, char*), com_charset(String *str,char*),
204
com_prompt(String *str, char*), com_delimiter(String *str, char*),
205
com_warnings(String *str, char*), com_nowarnings(String *str, char*);
201
static int com_quit(GString *str,char*),
202
com_go(GString *str,char*), com_ego(GString *str,char*),
203
com_print(GString *str,char*),
204
com_help(GString *str,char*), com_clear(GString *str,char*),
205
com_connect(GString *str,char*), com_status(GString *str,char*),
206
com_use(GString *str,char*), com_source(GString *str, char*),
207
com_rehash(GString *str, char*), com_tee(GString *str, char*),
208
com_notee(GString *str, char*), com_charset(GString *str,char*),
209
com_prompt(GString *str, char*), com_delimiter(GString *str, char*),
210
com_warnings(GString *str, char*), com_nowarnings(GString *str, char*);
208
static int com_nopager(String *str, char*), com_pager(String *str, char*),
209
com_edit(String *str,char*), com_shell(String *str, char *);
213
static int com_nopager(GString *str, char*), com_pager(GString *str, char*),
214
com_edit(GString *str,char*), com_shell(GString *str, char *);
212
217
static int read_and_execute(bool interactive);
1019
1023
extern "C" int history_length;
1020
1024
static int not_in_history(const char *line);
1021
1025
static void initialize_readline (char *name);
1022
static void fix_history(String *final_command);
1026
static void fix_history(GString *final_command);
1025
1028
static COMMANDS *find_command(char *name,char cmd_name);
1026
static bool add_line(String &buffer,char *line,char *in_string,
1029
static bool add_line(GString *buffer,char *line,char *in_string,
1027
1030
bool *ml_comment);
1028
static void remove_cntrl(String &buffer);
1031
static void remove_cntrl(GString *buffer);
1029
1032
static void print_table_data(MYSQL_RES *result);
1030
1033
static void print_table_data_html(MYSQL_RES *result);
1031
1034
static void print_table_data_xml(MYSQL_RES *result);
1143
1145
put_info("Welcome to the Drizzle client.. Commands end with ; or \\g.",
1145
sprintf((char*) glob_buffer.ptr(),
1146
"Your Drizzle connection id is %lu\nServer version: %s\n",
1147
mysql_thread_id(&mysql), server_version_string(&mysql));
1148
put_info((char*) glob_buffer.ptr(),INFO_INFO);
1147
glob_buffer = g_string_sized_new(512);
1148
g_string_printf(glob_buffer,
1149
"Your Drizzle connection id is %lu\nServer version: %s\n",
1150
mysql_thread_id(&mysql), server_version_string(&mysql));
1151
put_info(glob_buffer->str,INFO_INFO);
1150
#ifdef HAVE_READLINE
1151
1153
initialize_readline((char*) my_progname);
1152
1154
if (!status.batch && !quick && !opt_html && !opt_xml)
1157
1159
else if (getenv("HOME"))
1159
1161
histfile=(char*) my_malloc((uint) strlen(getenv("HOME"))
1160
+ (uint) strlen("/.mysql_history")+2,
1162
+ (uint) strlen("/.mysql_history")+2,
1163
sprintf(histfile,"%s/.mysql_history",getenv("HOME"));
1165
sprintf(histfile,"%s/.mysql_history",getenv("HOME"));
1164
1166
char link_name[FN_REFLEN];
1165
1167
if (my_readlink(link_name, histfile, 0) == 0 &&
1166
1168
strncmp(link_name, "/dev/null", 10) == 0)
1176
tee_fprintf(stdout, "Reading history-file %s\n",histfile);
1178
tee_fprintf(stdout, "Reading history-file %s\n",histfile);
1177
1179
read_history(histfile);
1178
1180
if (!(histfile_tmp= (char*) my_malloc((uint) strlen(histfile) + 5,
1181
fprintf(stderr, "Couldn't allocate memory for temp histfile!\n");
1183
fprintf(stderr, "Couldn't allocate memory for temp histfile!\n");
1184
1186
sprintf(histfile_tmp, "%s.TMP", histfile);
1188
1189
sprintf(buff, "%s",
1190
"Type 'help;' or '\\h' for help. Type '\\c' to clear the buffer.\n");
1192
"Type 'help [[%]function name[%]]' to get help on usage of function.\n");
1190
"Type 'help;' or '\\h' for help. Type '\\c' to clear the buffer.\n");
1194
1192
put_info(buff,INFO_INFO);
1195
1193
status.exit_status= read_and_execute(!status.batch);
1196
1194
if (opt_outfile)
1200
DBUG_RETURN(0); // Keep compiler happy
1204
1200
sig_handler mysql_end(int sig)
1206
1202
mysql_close(&mysql);
1207
#ifdef HAVE_READLINE
1208
1203
if (!status.batch && !quick && !opt_html && !opt_xml && histfile)
1210
1205
/* write-history */
1217
1212
completion_hash_free(&ht);
1218
1213
free_root(&hash_mem_root,MYF(0));
1222
1216
put_info(sig ? "Aborted" : "Bye", INFO_RESULT);
1225
processed_prompt.free();
1217
g_string_free(glob_buffer,true);
1218
g_string_free(old_buffer,true);
1219
g_string_free(processed_prompt,true);
1226
1220
my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
1227
1221
my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR));
1228
1222
my_free(histfile,MYF(MY_ALLOW_ZERO_PTR));
1495
1489
static void usage(int version)
1497
#if defined(USE_LIBEDIT_INTERFACE)
1498
const char* readline= "";
1500
1491
const char* readline= "readline";
1503
#ifdef HAVE_READLINE
1504
1493
printf("%s Ver %s Distrib %s, for %s (%s) using %s %s\n",
1505
my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE,
1494
my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE,
1506
1495
readline, rl_library_version);
1508
printf("%s Ver %s Distrib %s, for %s (%s)\n", my_progname, VER,
1509
MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
1817
1803
Check if line is a mysql command line
1818
1804
(We want to allow help, print and clear anywhere at line start
1820
if ((named_cmds || glob_buffer.is_empty())
1821
&& !ml_comment && !in_string && (com=find_command(line,0)))
1806
if ((named_cmds || (glob_buffer->len==0))
1807
&& !ml_comment && !in_string && (com=find_command(line,0)))
1823
if ((*com->func)(&glob_buffer,line) > 0)
1825
if (glob_buffer.is_empty()) // If buffer was emptied
1827
#ifdef HAVE_READLINE
1809
if ((*com->func)(glob_buffer,line) > 0)
1811
// If buffer was emptied
1812
if (glob_buffer->len==0)
1828
1814
if (interactive && status.add_to_history && not_in_history(line))
1833
1818
if (add_line(glob_buffer,line,&in_string,&ml_comment))
1954
1937
// Found possbile one character command like \c
1956
1939
if (!(inchar = (uchar) *++pos))
1957
break; // readline adds one '\'
1940
break; // readline adds one '\'
1958
1941
if (*in_string || inchar == 'N') // \N is short for NULL
1959
1942
{ // Don't allow commands in string
1961
*out++= (char) inchar;
1944
*out++= (char) inchar;
1964
1947
if ((com=find_command(NullS,(char) inchar)))
1966
1949
// Flush previously accepted characters
1967
1950
if (out != line)
1969
buffer.append(line, (uint) (out-line));
1952
g_string_append_len(buffer, line, (gssize) (out-line));
1973
if ((*com->func)(&buffer,pos-1) > 0)
1956
if ((*com->func)(buffer,pos-1) > 0)
1974
1957
DBUG_RETURN(1); // Quit
1975
1958
if (com->takes_params)
2016
1999
// Flush previously accepted characters
2017
2000
if (out != line)
2019
buffer.append(line, (uint32) (out - line));
2002
g_string_append_len(buffer, line, (gssize) (out - line));
2023
2006
// Flush possible comments in the buffer
2024
if (!buffer.is_empty())
2007
if (buffer->len > 0)
2026
if (com_go(&buffer, 0) > 0) // < 0 is not fatal
2009
if (com_go(buffer, 0) > 0) // < 0 is not fatal
2027
2010
DBUG_RETURN(1);
2011
g_string_truncate(buffer,0);
2032
2015
Delimiter wants the get rest of the given line as argument to
2033
2016
allow one to change ';' to ';;' and back
2036
if (com_delimiter(&buffer, pos) > 0)
2018
g_string_append(buffer,pos);
2019
if (com_delimiter(buffer, pos) > 0)
2037
2020
DBUG_RETURN(1);
2022
g_string_truncate(buffer,0);
2042
2025
else if (!*ml_comment && !*in_string && is_prefix(pos, delimiter))
2062
2045
my_isspace(charset_info, pos[2]))))
2064
2047
// Add trailing single line comments to this statement
2048
g_string_append(buffer, pos);
2066
2049
pos+= strlen(pos);
2071
if ((com= find_command(buffer.c_ptr(), 0)))
2054
if ((com= find_command(buffer->str, 0)))
2074
if ((*com->func)(&buffer, buffer.c_ptr()) > 0)
2057
if ((*com->func)(buffer, buffer->str) > 0)
2075
2058
DBUG_RETURN(1); // Quit
2079
if (com_go(&buffer, 0) > 0) // < 0 is not fatal
2062
if (com_go(buffer, 0) > 0) // < 0 is not fatal
2080
2063
DBUG_RETURN(1);
2065
g_string_truncate(buffer,0);
2084
else if (!*ml_comment && (!*in_string && (inchar == '#' ||
2085
(inchar == '-' && pos[1] == '-' && my_isspace(charset_info,pos[2])))))
2067
else if (!*ml_comment
2072
&& my_isspace(charset_info,pos[2])))))
2087
2074
// Flush previously accepted characters
2088
2075
if (out != line)
2090
buffer.append(line, (uint32) (out - line));
2077
g_string_append_len(buffer, line, (gssize) (out - line));
2094
2081
// comment to end of line
2095
2082
if (preserve_comments)
2083
g_string_append(buffer,pos);
2100
2087
else if (!*in_string && inchar == '/' && *(pos+1) == '*' &&
2103
2090
if (preserve_comments)
2126
2113
*ml_comment= 0;
2127
2114
if (out != line)
2129
buffer.append(line, (uint32) (out - line));
2116
g_string_append_len(buffer, line, (gssize) (out - line));
2132
2119
// Consumed a 2 chars or more, and will add 1 at most,
2133
2120
// so using the 'line' buffer to edit data in place is ok.
2137
{ // Add found char to buffer
2125
// Add found char to buffer
2138
2126
if (!*in_string && inchar == '/' && *(pos + 1) == '*' &&
2139
2127
*(pos + 2) == '!')
2141
2129
else if (!*in_string && ss_comment && inchar == '*' && *(pos + 1) == '/')
2143
2131
if (inchar == *in_string)
2145
2133
else if (!*ml_comment && !*in_string &&
2146
(inchar == '\'' || inchar == '"' || inchar == '`'))
2147
*in_string= (char) inchar;
2134
(inchar == '\'' || inchar == '"' || inchar == '`'))
2135
*in_string= (char) inchar;
2148
2136
if (!*ml_comment || preserve_comments)
2150
2138
if (need_space && !my_isspace(charset_info, (char)inchar))
2187
2173
extern "C" char *no_completion()
2190
return 0; /* No filename completion */
2176
/* No filename completion */
2193
/* glues pieces of history back together if in pieces */
2194
static void fix_history(String *final_command)
2180
/* glues pieces of history back together if in pieces */
2181
static void fix_history(GString *final_command)
2196
2183
int total_lines = 1;
2197
char *ptr = final_command->c_ptr();
2198
String fixed_buffer; /* Converted buffer */
2184
const char *ptr = final_command->str;
2185
/* Converted buffer */
2186
GString * fixed_buffer;
2187
fixed_buffer = g_string_sized_new(16);
2199
2188
char str_char = '\0'; /* Character if we are in a string or not */
2201
2190
/* find out how many lines we have and remove newlines */
2202
while (*ptr != '\0')
2191
while (*ptr != '\0')
2204
2193
switch (*ptr) {
2205
2194
/* string character */
2209
if (str_char == '\0') /* open string */
2199
if (str_char == '\0')
2211
2201
else if (str_char == *ptr) /* close string */
2213
fixed_buffer.append(ptr,1);
2203
g_string_append_len(fixed_buffer, ptr, 1);
2217
2207
not in string, change to space
2218
if in string, leave it alone
2208
if in string, leave it alone
2220
fixed_buffer.append(str_char == '\0' ? " " : "\n");
2210
g_string_append(fixed_buffer,(str_char == '\0') ? " " : "\n");
2224
fixed_buffer.append('\\');
2214
g_string_append_c(fixed_buffer, '\\');
2225
2215
/* need to see if the backslash is escaping anything */
2229
/* special characters that need escaping */
2230
if (*ptr == '\'' || *ptr == '"' || *ptr == '\\')
2231
fixed_buffer.append(ptr,1);
2219
/* special characters that need escaping */
2220
if (*ptr == '\'' || *ptr == '"' || *ptr == '\\')
2221
g_string_append_len(fixed_buffer, ptr, 1);
2238
fixed_buffer.append(ptr,1);
2227
g_string_append_len(fixed_buffer, ptr, 1);
2242
if (total_lines > 1)
2243
add_history(fixed_buffer.ptr());
2231
if (total_lines > 1)
2232
add_history(fixed_buffer->str);
2247
2236
returns 0 if line matches the previous history entry
2248
2237
returns 1 if the line doesn't match the previous history entry
2250
static int not_in_history(const char *line)
2239
static int not_in_history(const char *line)
2252
2241
HIST_ENTRY *oldhist = history_get(history_length);
2254
2243
if (oldhist == 0)
2256
2245
if (strcmp(oldhist->line,line) == 0)
2593
static int com_server_help(String *buffer __attribute__((unused)),
2594
char *line __attribute__((unused)), char *help_arg)
2581
static int com_server_help(GString *buffer,
2582
char *line __attribute__((unused)),
2597
const char *server_cmd= buffer->ptr();
2586
const char *server_cmd= buffer->str;
2598
2587
char cmd_buf[100];
2599
2588
MYSQL_RES *result;
2602
2591
if (help_arg[0] != '\'')
2604
char *end_arg= strend(help_arg);
2607
while (my_isspace(charset_info,*end_arg))
2611
(void) strxnmov(cmd_buf, sizeof(cmd_buf), "help '", help_arg, "'", NullS);
2593
char *end_arg= strend(help_arg);
2596
while (my_isspace(charset_info,*end_arg))
2600
(void) strxnmov(cmd_buf, sizeof(cmd_buf), "help '", help_arg, "'", NullS);
2612
2601
server_cmd= cmd_buf;
2615
2604
if (!status.batch)
2617
old_buffer= *buffer;
2606
old_buffer= g_string_new(buffer->str);
2621
2609
if (!connected && reconnect())
2762
2746
-1 if not fatal error
2763
2747
1 if fatal error
2768
com_go(String *buffer,char *line __attribute__((unused)))
2750
com_go(GString *buffer,
2751
char *line __attribute__((unused)))
2770
char buff[200]; /* about 110 chars used so far */
2771
char time_buff[52+3+1]; /* time max + space&parens + NUL */
2773
ulong timer, warnings= 0;
2753
char buff[200]; /* about 110 chars used so far */
2754
char time_buff[52+3+1]; /* time max + space&parens + NUL */
2756
ulong timer, warnings= 0;
2777
2760
interrupted_query= 0;
2778
2761
if (!status.batch)
2780
old_buffer= *buffer; // Save for edit command
2763
// Save for edit command
2764
old_buffer= g_string_new(buffer->str);
2784
2767
/* Remove garbage for nicer messages */
2785
remove_cntrl(*buffer);
2768
remove_cntrl(buffer);
2787
if (buffer->is_empty())
2770
if (buffer->len == 0)
2789
if (status.batch) // Ignore empty quries
2772
// Ignore empty quries
2791
2775
return put_info("No query specified\n",INFO_ERROR);
2794
2778
if (!connected && reconnect())
2796
buffer->length(0); // Remove query on error
2780
// Remove query on error
2781
g_string_truncate(buffer, 0);
2797
2782
return opt_reconnect ? -1 : 1; // Fatal error
2800
(void) com_print(buffer,0);
2785
(void) com_print(buffer, 0);
2802
2787
if (skip_updates &&
2803
(buffer->length() < 4 || my_strnncoll(charset_info,
2804
(const uchar*)buffer->ptr(),4,
2805
(const uchar*)"SET ",4)))
2789
|| g_string_equal(g_string_new_len(buffer->str,4),
2790
g_string_new("SET ")))
2807
2792
(void) put_info("Ignoring query to other database",INFO_INFO);
2811
2796
timer=start_timer();
2812
2797
executing_query= 1;
2813
error= mysql_real_query_for_lazy(buffer->ptr(),buffer->length());
2798
error= mysql_real_query_for_lazy(buffer->str,buffer->len);
2815
#ifdef HAVE_READLINE
2816
if (status.add_to_history)
2818
buffer->append(vertical ? "\\G" : delimiter);
2800
if (status.add_to_history)
2802
g_string_append(buffer, vertical ? "\\G" : delimiter);
2819
2803
/* Append final command onto history */
2820
2804
fix_history(buffer);
2807
g_string_truncate(buffer, 0);
3185
3169
if (num_flag[off] != 0) /* if it is numeric, we right-justify it */
3186
3170
tee_print_sized_data(buffer, data_length, field_max_length+extra_padding, TRUE);
3188
tee_print_sized_data(buffer, data_length, field_max_length+extra_padding, FALSE);
3172
tee_print_sized_data(buffer, data_length,
3173
field_max_length+extra_padding, FALSE);
3190
3175
tee_fputs(" | ", PAGER);
3192
3177
(void) tee_fputs("\n", PAGER);
3194
3179
tee_puts((char*) separator.ptr(), PAGER);
3195
my_afree((uchar*) num_flag);
3180
my_free(num_flag, MYF(MY_ALLOW_ZERO_PTR));
3199
3184
Return the length of a field after it would be rendered into text.
3201
3186
This doesn't know or care about multibyte characters. Assume we're
3202
using such a charset. We can't know that all of the upcoming rows
3187
using such a charset. We can't know that all of the upcoming rows
3203
3188
for this column will have bytes that each render into some fraction
3204
3189
of a character. It's at least possible that a row has bytes that
3205
3190
all render into one character each, and so the maximum length is