summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/client_priv.h3
-rw-r--r--client/mysql.cc260
-rw-r--r--client/mysql_upgrade.c13
-rw-r--r--client/mysqladmin.cc8
-rw-r--r--client/mysqlbinlog.cc11
-rw-r--r--client/mysqlcheck.c92
-rw-r--r--client/mysqldump.c44
-rw-r--r--client/mysqlimport.c8
-rw-r--r--client/mysqlshow.c8
-rw-r--r--client/mysqlslap.c18
-rw-r--r--client/mysqltest.c99
11 files changed, 433 insertions, 131 deletions
diff --git a/client/client_priv.h b/client/client_priv.h
index a2f61b9e9ca..c205d07c34c 100644
--- a/client/client_priv.h
+++ b/client/client_priv.h
@@ -80,5 +80,6 @@ enum options_client
OPT_MYSQL_REPLACE_INTO, OPT_BASE64_OUTPUT, OPT_SERVER_ID,
OPT_FIX_TABLE_NAMES, OPT_FIX_DB_NAMES, OPT_SSL_VERIFY_SERVER_CERT,
OPT_DEBUG_INFO, OPT_DEBUG_CHECK, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE,
- OPT_WRITE_BINLOG, OPT_MAX_CLIENT_OPTION
+ OPT_WRITE_BINLOG, OPT_DUMP_DATE,
+ OPT_MAX_CLIENT_OPTION
};
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);
}
diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c
index 334269720b4..fe2e48fdba1 100644
--- a/client/mysql_upgrade.c
+++ b/client/mysql_upgrade.c
@@ -96,8 +96,13 @@ 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.", 0,
- 0, 0, GET_STR, 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) ").",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"protocol", OPT_MYSQL_PROTOCOL,
"The protocol of connection (tcp,socket,pipe,memory).",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -462,7 +467,11 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res,
if (my_write(fd, (uchar*) query, strlen(query),
MYF(MY_FNABP | MY_WME)))
+ {
+ my_close(fd, MYF(0));
+ my_delete(query_file_path, MYF(0));
die("Failed to write to '%s'", query_file_path);
+ }
ret= run_tool(mysql_path,
ds_res,
diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc
index 0375e84b458..01329c550d6 100644
--- a/client/mysqladmin.cc
+++ b/client/mysqladmin.cc
@@ -173,7 +173,13 @@ 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**) &tcp_port,
+ {"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**) &tcp_port,
(uchar**) &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 12d1da39974..7a4135ab649 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -760,9 +760,14 @@ static struct my_option my_long_options[] =
0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"password", 'p', "Password to connect to remote server.",
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"port", 'P', "Use port to connect to the remote server.",
- (uchar**) &port, (uchar**) &port, 0, GET_INT, 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**) &port, (uchar**) &port, 0, GET_INT, REQUIRED_ARG,
+ 0, 0, 0, 0, 0, 0},
{"position", 'j', "Deprecated. Use --start-position instead.",
(uchar**) &start_position, (uchar**) &start_position, 0, GET_ULL,
REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE,
diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c
index 316412d7df9..3350bfa17a7 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -142,7 +142,13 @@ 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,
+ {"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},
{"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
@@ -200,6 +206,7 @@ static void dbDisconnect(char *host);
static void DBerror(MYSQL *mysql, const char *when);
static void safe_exit(int error);
static void print_result();
+static uint fixed_name_length(const char *name);
static char *fix_table_name(char *dest, char *src);
int what_to_do = 0;
@@ -432,14 +439,14 @@ static int process_selected_tables(char *db, char **table_names, int tables)
{
/*
We need table list in form `a`, `b`, `c`
- that's why we need 4 more chars added to to each table name
+ that's why we need 2 more chars added to to each table name
space is for more readable output in logs and in case of error
*/
char *table_names_comma_sep, *end;
int i, tot_length = 0;
for (i = 0; i < tables; i++)
- tot_length += strlen(*(table_names + i)) + 4;
+ tot_length+= fixed_name_length(*(table_names + i)) + 2;
if (!(table_names_comma_sep = (char *)
my_malloc((sizeof(char) * tot_length) + 4, MYF(MY_WME))))
@@ -457,23 +464,46 @@ static int process_selected_tables(char *db, char **table_names, int tables)
}
else
for (; tables > 0; tables--, table_names++)
- handle_request_for_tables(*table_names, strlen(*table_names));
+ handle_request_for_tables(*table_names, fixed_name_length(*table_names));
return 0;
} /* process_selected_tables */
-static char *fix_table_name(char *dest, char *src)
+static uint fixed_name_length(const char *name)
{
- char *db_sep;
+ const char *p;
+ uint extra_length= 2; /* count the first/last backticks */
+
+ for (p= name; *p; p++)
+ {
+ if (*p == '`')
+ extra_length++;
+ else if (*p == '.')
+ extra_length+= 2;
+ }
+ return (p - name) + extra_length;
+}
+
+static char *fix_table_name(char *dest, char *src)
+{
*dest++= '`';
- if ((db_sep= strchr(src, '.')))
+ for (; *src; src++)
{
- dest= strmake(dest, src, (uint) (db_sep - src));
- dest= strmov(dest, "`.`");
- src= db_sep + 1;
+ switch (*src) {
+ case '.': /* add backticks around '.' */
+ *dest++= '`';
+ *dest++= '.';
+ *dest++= '`';
+ break;
+ case '`': /* escape backtick character */
+ *dest++= '`';
+ /* fall through */
+ default:
+ *dest++= *src;
+ }
}
- dest= strxmov(dest, src, "`", NullS);
+ *dest++= '`';
return dest;
}
@@ -494,7 +524,7 @@ static int process_all_tables_in_db(char *database)
{
/*
We need table list in form `a`, `b`, `c`
- that's why we need 4 more chars added to to each table name
+ that's why we need 2 more chars added to to each table name
space is for more readable output in logs and in case of error
*/
@@ -502,7 +532,7 @@ static int process_all_tables_in_db(char *database)
uint tot_length = 0;
while ((row = mysql_fetch_row(res)))
- tot_length += strlen(row[0]) + 4;
+ tot_length+= fixed_name_length(row[0]) + 2;
mysql_data_seek(res, 0);
if (!(tables=(char *) my_malloc(sizeof(char)*tot_length+4, MYF(MY_WME))))
@@ -527,10 +557,13 @@ static int process_all_tables_in_db(char *database)
else
{
while ((row = mysql_fetch_row(res)))
- /* Skip tables with an engine of NULL (probably a view). */
- if (row[1])
+ /*
+ Skip tables with an engine of NULL (probably a view)
+ if we don't perform renaming.
+ */
+ if (row[1] || what_to_do == DO_UPGRADE)
{
- handle_request_for_tables(row[0], strlen(row[0]));
+ handle_request_for_tables(row[0], fixed_name_length(row[0]));
}
}
mysql_free_result(res);
@@ -539,13 +572,13 @@ static int process_all_tables_in_db(char *database)
-static int fix_object_name(const char *obj, const char *name)
+static int fix_table_storage_name(const char *name)
{
char qbuf[100 + NAME_LEN*4];
int rc= 0;
if (strncmp(name, "#mysql50#", 9))
return 1;
- sprintf(qbuf, "RENAME %s `%s` TO `%s`", obj, name, name + 9);
+ sprintf(qbuf, "RENAME TABLE `%s` TO `%s`", name, name + 9);
if (mysql_query(sock, qbuf))
{
fprintf(stderr, "Failed to %s\n", qbuf);
@@ -557,6 +590,23 @@ static int fix_object_name(const char *obj, const char *name)
return rc;
}
+static int fix_database_storage_name(const char *name)
+{
+ char qbuf[100 + NAME_LEN*4];
+ int rc= 0;
+ if (strncmp(name, "#mysql50#", 9))
+ return 1;
+ sprintf(qbuf, "ALTER DATABASE `%s` UPGRADE DATA DIRECTORY NAME", name);
+ if (mysql_query(sock, qbuf))
+ {
+ fprintf(stderr, "Failed to %s\n", qbuf);
+ fprintf(stderr, "Error: %s\n", mysql_error(sock));
+ rc= 1;
+ }
+ if (verbose)
+ printf("%-50s %s\n", name, rc ? "FAILED" : "OK");
+ return rc;
+}
static int process_one_db(char *database)
{
@@ -565,7 +615,7 @@ static int process_one_db(char *database)
int rc= 0;
if (opt_fix_db_names && !strncmp(database,"#mysql50#", 9))
{
- rc= fix_object_name("DATABASE", database);
+ rc= fix_database_storage_name(database);
database+= 9;
}
if (rc || !opt_fix_table_names)
@@ -620,7 +670,7 @@ static int handle_request_for_tables(char *tables, uint length)
op= (opt_write_binlog) ? "OPTIMIZE" : "OPTIMIZE NO_WRITE_TO_BINLOG";
break;
case DO_UPGRADE:
- return fix_object_name("TABLE", tables);
+ return fix_table_storage_name(tables);
}
if (!(query =(char *) my_malloc((sizeof(char)*(length+110)), MYF(MY_WME))))
@@ -803,7 +853,7 @@ int main(int argc, char **argv)
for (i = 0; i < tables4repair.elements ; i++)
{
char *name= (char*) dynamic_array_ptr(&tables4repair, i);
- handle_request_for_tables(name, strlen(name));
+ handle_request_for_tables(name, fixed_name_length(name));
}
}
end:
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 582e9e3b3b9..01b484e924e 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -90,7 +90,7 @@ static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0,
opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0,
opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0,
opt_alldbs=0,opt_create_db=0,opt_lock_all_tables=0,
- opt_set_charset=0,
+ opt_set_charset=0, opt_dump_date=1,
opt_autocommit=0,opt_disable_keys=1,opt_xml=0,
opt_delete_master_logs=0, tty_password=0,
opt_single_transaction=0, opt_comments= 0, opt_compact= 0,
@@ -420,10 +420,17 @@ static struct my_option my_long_options[] =
"Creates a consistent snapshot by dumping all tables in a single "
"transaction. Works ONLY for tables stored in storage engines which "
"support multiversioning (currently only InnoDB does); the dump is NOT "
- "guaranteed to be consistent for other storage engines. Option "
- "automatically turns off --lock-tables.",
+ "guaranteed to be consistent for other storage engines. "
+ "While a --single-transaction dump is in process, to ensure a valid "
+ "dump file (correct table contents and binary log position), no other "
+ "connection should use the following statements: ALTER TABLE, DROP "
+ "TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not "
+ "isolated from them. Option automatically turns off --lock-tables.",
(uchar**) &opt_single_transaction, (uchar**) &opt_single_transaction, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"dump-date", OPT_DUMP_DATE, "Put a dump date to the end of the output.",
+ (uchar**) &opt_dump_date, (uchar**) &opt_dump_date, 0,
+ GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"skip-opt", OPT_SKIP_OPTIMIZATION,
"Disable --opt. Disables --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -651,10 +658,15 @@ static void write_footer(FILE *sql_file)
fputs("\n", sql_file);
if (opt_comments)
{
- char time_str[20];
- get_date(time_str, GETDATE_DATE_TIME, 0);
- fprintf(sql_file, "-- Dump completed on %s\n",
- time_str);
+ if (opt_dump_date)
+ {
+ char time_str[20];
+ get_date(time_str, GETDATE_DATE_TIME, 0);
+ fprintf(sql_file, "-- Dump completed on %s\n",
+ time_str);
+ }
+ else
+ fprintf(sql_file, "-- Dump completed\n");
}
check_io(sql_file);
}
@@ -1032,8 +1044,10 @@ static int fetch_db_collation(const char *db_name,
char query[QUERY_LENGTH];
MYSQL_RES *db_cl_res;
MYSQL_ROW db_cl_row;
+ char quoted_database_buf[NAME_LEN*2+3];
+ char *qdatabase= quote_name(db_name, quoted_database_buf, 1);
- my_snprintf(query, sizeof (query), "use %s", db_name);
+ my_snprintf(query, sizeof (query), "use %s", qdatabase);
if (mysql_query_with_error_report(mysql, NULL, query))
return 1;
@@ -1888,7 +1902,7 @@ static uint dump_events_for_db(char *db)
if (create_delimiter(row[3], delimiter, sizeof(delimiter)) == NULL)
{
fprintf(stderr, "%s: Warning: Can't create delimiter for event '%s'\n",
- event_name, my_progname);
+ my_progname, event_name);
DBUG_RETURN(1);
}
@@ -4369,6 +4383,18 @@ static int start_transaction(MYSQL *mysql_con)
need the REPEATABLE READ level (not anything lower, for example READ
COMMITTED would give one new consistent read per dumped table).
*/
+ if ((mysql_get_server_version(mysql_con) < 40100) && opt_master_data)
+ {
+ fprintf(stderr, "-- %s: the combination of --single-transaction and "
+ "--master-data requires a MySQL server version of at least 4.1 "
+ "(current server's version is %s). %s\n",
+ ignore_errors ? "Warning" : "Error",
+ mysql_con->server_version ? mysql_con->server_version : "unknown",
+ ignore_errors ? "Continuing due to --force, backup may not be consistent across all tables!" : "Aborting.");
+ if (!ignore_errors)
+ exit(EX_MYSQLERR);
+ }
+
return (mysql_query_with_error_report(mysql_con, 0,
"SET SESSION TRANSACTION ISOLATION "
"LEVEL REPEATABLE READ") ||
diff --git a/client/mysqlimport.c b/client/mysqlimport.c
index afd9454d6be..954af0cff97 100644
--- a/client/mysqlimport.c
+++ b/client/mysqlimport.c
@@ -137,7 +137,13 @@ 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,
+ {"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},
{"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
diff --git a/client/mysqlshow.c b/client/mysqlshow.c
index a7f6cadf450..a43adb0d586 100644
--- a/client/mysqlshow.c
+++ b/client/mysqlshow.c
@@ -196,7 +196,13 @@ static struct my_option my_long_options[] =
{"password", 'p',
"Password to use when connecting to server. If password is not given it's asked from the tty.",
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"port", 'P', "Port number to use for connection.", (uchar**) &opt_mysql_port,
+ {"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},
#ifdef __WIN__
diff --git a/client/mysqlslap.c b/client/mysqlslap.c
index 02a0cbd04c5..1c54ba86718 100644
--- a/client/mysqlslap.c
+++ b/client/mysqlslap.c
@@ -140,7 +140,8 @@ static my_bool opt_compress= FALSE, tty_password= FALSE,
auto_generate_sql= FALSE;
const char *auto_generate_sql_type= "mixed";
-static unsigned long connect_flags= CLIENT_MULTI_RESULTS;
+static unsigned long connect_flags= CLIENT_MULTI_RESULTS |
+ CLIENT_MULTI_STATEMENTS;
static int verbose, delimiter_length;
static uint commit_rate;
@@ -1877,13 +1878,16 @@ limit_not_met:
}
}
- if (mysql_field_count(mysql))
+ do
{
- result= mysql_store_result(mysql);
- while ((row = mysql_fetch_row(result)))
- counter++;
- mysql_free_result(result);
- }
+ if (mysql_field_count(mysql))
+ {
+ result= mysql_store_result(mysql);
+ while ((row = mysql_fetch_row(result)))
+ counter++;
+ mysql_free_result(result);
+ }
+ } while(mysql_next_result(mysql) == 0);
queries++;
if (commit_rate && commit_rate <= trans_counter)
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 558763f7cff..f74a3bf506b 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -271,7 +271,7 @@ enum enum_commands {
Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST,
Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_SKIP,
Q_CHMOD_FILE, Q_APPEND_FILE, Q_CAT_FILE, Q_DIFF_FILES,
- Q_SEND_QUIT,
+ Q_SEND_QUIT, Q_CHANGE_USER,
Q_UNKNOWN, /* Unknown command. */
Q_COMMENT, /* Comments, ignored. */
@@ -360,6 +360,7 @@ const char *command_names[]=
"cat_file",
"diff_files",
"send_quit",
+ "change_user",
0
};
@@ -1515,7 +1516,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
die("Failed to create temporary file for ds");
/* Write ds to temporary file and set file pos to beginning*/
- if (my_write(fd, ds->str, ds->length,
+ if (my_write(fd, (uchar *) ds->str, ds->length,
MYF(MY_FNABP | MY_WME)) ||
my_seek(fd, 0, SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR)
{
@@ -1597,10 +1598,22 @@ void check_result(DYNAMIC_STRING* ds)
and then show the diff
*/
char reject_file[FN_REFLEN];
- str_to_file(fn_format(reject_file, result_file_name, opt_logdir, ".reject",
- *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
- MY_REPLACE_EXT),
- ds->str, ds->length);
+ size_t reject_length;
+ dirname_part(reject_file, result_file_name, &reject_length);
+
+ if (access(reject_file, W_OK) == 0)
+ {
+ /* Result file directory is writable, save reject file there */
+ fn_format(reject_file, result_file_name, NULL,
+ ".reject", MY_REPLACE_EXT);
+ }
+ else
+ {
+ /* Put reject file in opt_logdir */
+ fn_format(reject_file, result_file_name, opt_logdir,
+ ".reject", MY_REPLACE_DIR | MY_REPLACE_EXT);
+ }
+ str_to_file(reject_file, ds->str, ds->length);
dynstr_set(ds, NULL); /* Don't create a .log file */
@@ -2691,7 +2704,7 @@ void do_copy_file(struct st_command *command)
command command handle
DESCRIPTION
- chmod_file <octal> <file_name>
+ chmod <octal> <file_name>
Change file permission of <file_name>
*/
@@ -3064,6 +3077,69 @@ void do_send_quit(struct st_command *command)
/*
SYNOPSIS
+ do_change_user
+ command called command
+
+ DESCRIPTION
+ change_user [<user>], [<passwd>], [<db>]
+ <user> - user to change to
+ <passwd> - user password
+ <db> - default database
+
+ Changes the user and causes the database specified by db to become
+ the default (current) database for the the current connection.
+
+*/
+
+void do_change_user(struct st_command *command)
+{
+ MYSQL *mysql = &cur_con->mysql;
+ /* static keyword to make the NetWare compiler happy. */
+ static DYNAMIC_STRING ds_user, ds_passwd, ds_db;
+ const struct command_arg change_user_args[] = {
+ { "user", ARG_STRING, FALSE, &ds_user, "User to connect as" },
+ { "password", ARG_STRING, FALSE, &ds_passwd, "Password used when connecting" },
+ { "database", ARG_STRING, FALSE, &ds_db, "Database to select after connect" },
+ };
+
+ DBUG_ENTER("do_change_user");
+
+ check_command_args(command, command->first_argument,
+ change_user_args,
+ sizeof(change_user_args)/sizeof(struct command_arg),
+ ',');
+
+ if (cur_con->stmt)
+ {
+ mysql_stmt_close(cur_con->stmt);
+ cur_con->stmt= NULL;
+ }
+
+ if (!ds_user.length)
+ dynstr_set(&ds_user, mysql->user);
+
+ if (!ds_passwd.length)
+ dynstr_set(&ds_passwd, mysql->passwd);
+
+ if (!ds_db.length)
+ dynstr_set(&ds_db, mysql->db);
+
+ DBUG_PRINT("info",("connection: '%s' user: '%s' password: '%s' database: '%s'",
+ cur_con->name, ds_user.str, ds_passwd.str, ds_db.str));
+
+ if (mysql_change_user(mysql, ds_user.str, ds_passwd.str, ds_db.str))
+ die("change user failed: %s", mysql_error(mysql));
+
+ dynstr_free(&ds_user);
+ dynstr_free(&ds_passwd);
+ dynstr_free(&ds_db);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ SYNOPSIS
do_perl
command command handle
@@ -4985,7 +5061,13 @@ static struct my_option my_long_options[] =
GET_INT, REQUIRED_ARG, 500, 1, 10000, 0, 0, 0},
{"password", 'p', "Password to use when connecting to server.",
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"port", 'P', "Port number to use for connection.", (uchar**) &opt_port,
+ {"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_port,
(uchar**) &opt_port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ps-protocol", OPT_PS_PROTOCOL, "Use prepared statements protocol for communication",
(uchar**) &ps_protocol, (uchar**) &ps_protocol, 0,
@@ -6885,6 +6967,7 @@ int main(int argc, char **argv)
case Q_APPEND_FILE: do_append_file(command); break;
case Q_DIFF_FILES: do_diff_files(command); break;
case Q_SEND_QUIT: do_send_quit(command); break;
+ case Q_CHANGE_USER: do_change_user(command); break;
case Q_CAT_FILE: do_cat_file(command); break;
case Q_COPY_FILE: do_copy_file(command); break;
case Q_CHMOD_FILE: do_chmod_file(command); break;