summaryrefslogtreecommitdiff
path: root/client/mysql.cc
diff options
context:
space:
mode:
Diffstat (limited to 'client/mysql.cc')
-rw-r--r--client/mysql.cc260
1 files changed, 183 insertions, 77 deletions
diff --git a/client/mysql.cc b/client/mysql.cc
index 794f252853a..d30b60732bc 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -144,6 +144,7 @@ static my_bool ignore_errors=0,wait_flag=0,quick=0,
show_warnings= 0, executing_query= 0, interrupted_query= 0;
static my_bool debug_info_flag, debug_check_flag;
static my_bool column_types_flag;
+static my_bool preserve_comments= 0;
static ulong opt_max_allowed_packet, opt_net_buffer_length;
static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0;
static uint my_end_arg;
@@ -604,6 +605,10 @@ static struct my_option my_long_options[] =
{"column-type-info", OPT_COLUMN_TYPES, "Display column type information.",
(uchar**) &column_types_flag, (uchar**) &column_types_flag,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"comments", 'c', "Preserve comments. Send comments to the server."
+ " The default is --skip-comments (discard comments), enable with --comments",
+ (uchar**) &preserve_comments, (uchar**) &preserve_comments,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"compress", 'C', "Use compression in server/client protocol.",
(uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
@@ -692,9 +697,14 @@ static struct my_option my_long_options[] =
{"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
- {"port", 'P', "Port number to use for connection.", (uchar**) &opt_mysql_port,
- (uchar**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
- 0},
+ {"port", 'P', "Port number to use for connection or 0 for default to, in "
+ "order of preference, my.cnf, $MYSQL_TCP_PORT, "
+#if MYSQL_PORT_DEFAULT == 0
+ "/etc/services, "
+#endif
+ "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
+ (uchar**) &opt_mysql_port,
+ (uchar**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"prompt", OPT_PROMPT, "Set the mysql prompt to this value.",
(uchar**) &current_prompt, (uchar**) &current_prompt, 0, GET_STR_ALLOC,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -749,9 +759,9 @@ static struct my_option my_long_options[] =
0, 0},
{"max_allowed_packet", OPT_MAX_ALLOWED_PACKET,
"Max packet length to send to, or receive from server",
- (uchar**) &opt_max_allowed_packet, (uchar**) &opt_max_allowed_packet, 0, GET_ULONG,
- REQUIRED_ARG, 16 *1024L*1024L, 4096, (longlong) 2*1024L*1024L*1024L,
- MALLOC_OVERHEAD, 1024, 0},
+ (uchar**) &opt_max_allowed_packet, (uchar**) &opt_max_allowed_packet, 0,
+ GET_ULONG, REQUIRED_ARG, 16 *1024L*1024L, 4096,
+ (longlong) 2*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
{"net_buffer_length", OPT_NET_BUFFER_LENGTH,
"Buffer for TCP/IP and socket communication",
(uchar**) &opt_net_buffer_length, (uchar**) &opt_net_buffer_length, 0, GET_ULONG,
@@ -759,12 +769,13 @@ static struct my_option my_long_options[] =
{"select_limit", OPT_SELECT_LIMIT,
"Automatic limit for SELECT when using --safe-updates",
(uchar**) &select_limit,
- (uchar**) &select_limit, 0, GET_ULONG, REQUIRED_ARG, 1000L, 1, ~0L, 0, 1, 0},
+ (uchar**) &select_limit, 0, GET_ULONG, REQUIRED_ARG, 1000L, 1, ULONG_MAX,
+ 0, 1, 0},
{"max_join_size", OPT_MAX_JOIN_SIZE,
"Automatic limit for rows in a join when using --safe-updates",
(uchar**) &max_join_size,
- (uchar**) &max_join_size, 0, GET_ULONG, REQUIRED_ARG, 1000000L, 1, ~0L, 0, 1,
- 0},
+ (uchar**) &max_join_size, 0, GET_ULONG, REQUIRED_ARG, 1000000L, 1, ULONG_MAX,
+ 0, 1, 0},
{"secure-auth", OPT_SECURE_AUTH, "Refuse client connecting to server if it"
" uses old (pre-4.1.1) protocol", (uchar**) &opt_secure_auth,
(uchar**) &opt_secure_auth, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -1082,6 +1093,17 @@ static int read_and_execute(bool interactive)
if (!interactive)
{
line=batch_readline(status.line_buff);
+ /*
+ Skip UTF8 Byte Order Marker (BOM) 0xEFBBBF.
+ Editors like "notepad" put this marker in
+ the very beginning of a text file when
+ you save the file using "Unicode UTF-8" format.
+ */
+ if (!line_number &&
+ (uchar) line[0] == 0xEF &&
+ (uchar) line[1] == 0xBB &&
+ (uchar) line[2] == 0xBF)
+ line+= 3;
line_number++;
if (!glob_buffer.length())
status.query_start_line=line_number;
@@ -1149,10 +1171,6 @@ static int read_and_execute(bool interactive)
status.exit_status=0;
break;
}
- if (!in_string && (line[0] == '#' ||
- (line[0] == '-' && line[1] == '-') ||
- line[0] == 0))
- continue; // Skip comment lines
/*
Check if line is a mysql command line
@@ -1278,15 +1296,21 @@ static bool add_line(String &buffer,char *line,char *in_string,
for (pos=out=line ; (inchar= (uchar) *pos) ; pos++)
{
- if (my_isspace(charset_info,inchar) && out == line &&
- buffer.is_empty())
- continue;
+ if (!preserve_comments)
+ {
+ // Skip spaces at the beggining of a statement
+ if (my_isspace(charset_info,inchar) && (out == line) &&
+ buffer.is_empty())
+ continue;
+ }
+
#ifdef USE_MB
+ // Accept multi-byte characters as-is
int length;
if (use_mb(charset_info) &&
(length= my_ismbchar(charset_info, pos, end_of_line)))
{
- if (!*ml_comment)
+ if (!*ml_comment || preserve_comments)
{
while (length--)
*out++ = *pos++;
@@ -1312,8 +1336,13 @@ static bool add_line(String &buffer,char *line,char *in_string,
}
if ((com=find_command(NullS,(char) inchar)))
{
- const String tmp(line,(uint) (out-line), charset_info);
- buffer.append(tmp);
+ // Flush previously accepted characters
+ if (out != line)
+ {
+ buffer.append(line, (uint) (out-line));
+ out= line;
+ }
+
if ((*com->func)(&buffer,pos-1) > 0)
DBUG_RETURN(1); // Quit
if (com->takes_params)
@@ -1341,7 +1370,6 @@ static bool add_line(String &buffer,char *line,char *in_string,
pos+= delimiter_length - 1; // Point at last delim char
}
}
- out=line;
}
else
{
@@ -1354,46 +1382,105 @@ static bool add_line(String &buffer,char *line,char *in_string,
}
}
else if (!*ml_comment && !*in_string &&
- (*pos == *delimiter && is_prefix(pos + 1, delimiter + 1) ||
- buffer.length() == 0 && (out - line) >= 9 &&
- !my_strcasecmp(charset_info, line, "delimiter")))
- {
- uint old_delimiter_length= delimiter_length;
+ strlen(pos) >= 10 &&
+ !my_strnncoll(charset_info, (uchar*) pos, 10,
+ (const uchar*) "delimiter ", 10))
+ {
+ // Flush previously accepted characters
+ if (out != line)
+ {
+ buffer.append(line, (uint32) (out - line));
+ out= line;
+ }
+
+ // Flush possible comments in the buffer
+ if (!buffer.is_empty())
+ {
+ if (com_go(&buffer, 0) > 0) // < 0 is not fatal
+ DBUG_RETURN(1);
+ buffer.length(0);
+ }
+
+ /*
+ Delimiter wants the get rest of the given line as argument to
+ allow one to change ';' to ';;' and back
+ */
+ buffer.append(pos);
+ if (com_delimiter(&buffer, pos) > 0)
+ DBUG_RETURN(1);
+
+ buffer.length(0);
+ break;
+ }
+ else if (!*ml_comment && !*in_string && is_prefix(pos, delimiter))
+ {
+ // Found a statement. Continue parsing after the delimiter
+ pos+= delimiter_length;
+
+ if (preserve_comments)
+ {
+ while (my_isspace(charset_info, *pos))
+ *out++= *pos++;
+ }
+ // Flush previously accepted characters
if (out != line)
- buffer.append(line, (uint) (out - line)); // Add this line
+ {
+ buffer.append(line, (uint32) (out-line));
+ out= line;
+ }
+
+ if (preserve_comments && ((*pos == '#') ||
+ ((*pos == '-') &&
+ (pos[1] == '-') &&
+ my_isspace(charset_info, pos[2]))))
+ {
+ // Add trailing single line comments to this statement
+ buffer.append(pos);
+ pos+= strlen(pos);
+ }
+
+ pos--;
+
if ((com= find_command(buffer.c_ptr(), 0)))
{
- if (com->func == com_delimiter)
- {
- /*
- Delimiter wants the get rest of the given line as argument to
- allow one to change ';' to ';;' and back
- */
- char *end= strend(pos);
- buffer.append(pos, (uint) (end - pos));
- /* Ensure pos will point at \0 after the pos+= below */
- pos= end - old_delimiter_length + 1;
- }
- if ((*com->func)(&buffer, buffer.c_ptr()) > 0)
- DBUG_RETURN(1); // Quit
+
+ if ((*com->func)(&buffer, buffer.c_ptr()) > 0)
+ DBUG_RETURN(1); // Quit
}
else
{
- if (com_go(&buffer, 0) > 0) // < 0 is not fatal
- DBUG_RETURN(1);
+ if (com_go(&buffer, 0) > 0) // < 0 is not fatal
+ DBUG_RETURN(1);
}
buffer.length(0);
- out= line;
- pos+= old_delimiter_length - 1;
}
else if (!*ml_comment && (!*in_string && (inchar == '#' ||
inchar == '-' && pos[1] == '-' &&
my_isspace(charset_info,pos[2]))))
- break; // comment to end of line
+ {
+ // Flush previously accepted characters
+ if (out != line)
+ {
+ buffer.append(line, (uint32) (out - line));
+ out= line;
+ }
+
+ // comment to end of line
+ if (preserve_comments)
+ buffer.append(pos);
+
+ break;
+ }
else if (!*in_string && inchar == '/' && *(pos+1) == '*' &&
*(pos+2) != '!')
{
- pos++;
+ if (preserve_comments)
+ {
+ *out++= *pos++; // copy '/'
+ *out++= *pos; // copy '*'
+ }
+ else
+ pos++;
*ml_comment= 1;
if (out != line)
{
@@ -1403,8 +1490,21 @@ static bool add_line(String &buffer,char *line,char *in_string,
}
else if (*ml_comment && !ss_comment && inchar == '*' && *(pos + 1) == '/')
{
- pos++;
+ if (preserve_comments)
+ {
+ *out++= *pos++; // copy '*'
+ *out++= *pos; // copy '/'
+ }
+ else
+ pos++;
*ml_comment= 0;
+ if (out != line)
+ {
+ buffer.append(line, (uint32) (out - line));
+ out= line;
+ }
+ // Consumed a 2 chars or more, and will add 1 at most,
+ // so using the 'line' buffer to edit data in place is ok.
need_space= 1;
}
else
@@ -1419,14 +1519,12 @@ static bool add_line(String &buffer,char *line,char *in_string,
else if (!*ml_comment && !*in_string &&
(inchar == '\'' || inchar == '"' || inchar == '`'))
*in_string= (char) inchar;
- if (!*ml_comment)
+ if (!*ml_comment || preserve_comments)
{
if (need_space && !my_isspace(charset_info, (char)inchar))
- {
*out++= ' ';
- need_space= 0;
- }
- *out++= (char) inchar;
+ need_space= 0;
+ *out++= (char) inchar;
}
}
}
@@ -1436,7 +1534,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
uint length=(uint) (out-line);
if (buffer.length() + length >= buffer.alloced_length())
buffer.realloc(buffer.length()+length+IO_SIZE);
- if (!(*ml_comment) && buffer.append(line,length))
+ if ((!*ml_comment || preserve_comments) && buffer.append(line, length))
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -2069,7 +2167,7 @@ com_go(String *buffer,char *line __attribute__((unused)))
{
char buff[200], time_buff[32], *pos;
MYSQL_RES *result;
- ulong timer, warnings;
+ ulong timer, warnings= 0;
uint error= 0;
int err= 0;
@@ -2121,33 +2219,26 @@ com_go(String *buffer,char *line __attribute__((unused)))
}
#endif
- if (error)
- {
- executing_query= 0;
- buffer->length(0); // Remove query on error
- return error;
- }
- error=0;
buffer->length(0);
+ if (error)
+ goto end;
+
do
{
if (quick)
{
if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql))
{
- executing_query= 0;
- return put_error(&mysql);
+ error= put_error(&mysql);
+ goto end;
}
}
else
{
error= mysql_store_result_for_lazy(&result);
if (error)
- {
- executing_query= 0;
- return error;
- }
+ goto end;
}
if (verbose >= 3 || !opt_silent)
@@ -2224,12 +2315,11 @@ com_go(String *buffer,char *line __attribute__((unused)))
if (err >= 1)
error= put_error(&mysql);
- if (show_warnings == 1 && warnings >= 1) /* Show warnings if any */
- {
- init_pager();
+end:
+
+ /* Show warnings if any or error occured */
+ if (show_warnings == 1 && (warnings >= 1 || error))
print_warnings();
- end_pager();
- }
if (!error && !status.batch &&
(mysql.server_status & SERVER_STATUS_DB_DROPPED))
@@ -2361,6 +2451,7 @@ static char *fieldflags2str(uint f) {
ff2s_check_flag(GROUP);
ff2s_check_flag(UNIQUE);
ff2s_check_flag(BINCMP);
+ ff2s_check_flag(ON_UPDATE_NOW);
#undef ff2s_check_flag
if (f)
sprintf(s, " unknows=0x%04x", f);
@@ -2653,6 +2744,9 @@ static void print_warnings()
MYSQL_RES *result;
MYSQL_ROW cur;
my_ulonglong num_rows;
+
+ /* Save current error before calling "show warnings" */
+ uint error= mysql_errno(&mysql);
/* Get the warnings */
query= "show warnings";
@@ -2661,16 +2755,28 @@ static void print_warnings()
/* Bail out when no warnings */
if (!(num_rows= mysql_num_rows(result)))
- {
- mysql_free_result(result);
- return;
- }
+ goto end;
+
+ cur= mysql_fetch_row(result);
+
+ /*
+ Don't print a duplicate of the current error. It is possible for SHOW
+ WARNINGS to return multiple errors with the same code, but different
+ messages. To be safe, skip printing the duplicate only if it is the only
+ warning.
+ */
+ if (!cur || num_rows == 1 && error == (uint) strtoul(cur[1], NULL, 10))
+ goto end;
/* Print the warnings */
- while ((cur= mysql_fetch_row(result)))
+ init_pager();
+ do
{
tee_fprintf(PAGER, "%s (Code %s): %s\n", cur[0], cur[1], cur[2]);
- }
+ } while ((cur= mysql_fetch_row(result)));
+ end_pager();
+
+end:
mysql_free_result(result);
}