Commit f820334b authored by Nirbhay Choubey's avatar Nirbhay Choubey

Bug#14645196 MYSQL CLIENT'S USE COMMAND FAILS

WHEN DBNAME CONTAINS MULTIPLE QUOTES

MySQL client's USE command might fail if the
database name contains multiple quotes (backticks).

The reason behind the failure being the method
that client uses to remove/escape the quotes
while parsing the USE command's option (dbname),
where the option parsing might terminate if a
matching quote is found.

Also, C-APIs like mysql_select_db() expect a
normalized dbname. Now, in certain cases, client
might fail to normalize dbname similar to that of
server and hence mysql_select_db() would fail.

Fixed by getting the normalized dbname (indirectly)
from the server by directly sending the "USE dbanme"
as query to the server followed by a "SELECT DATABASE()".
The above steps are only performed if number of quotes
in the dbname is greater than 2. Once the normalized
dbname is received, the original db is restored.
parent 373c428f
...@@ -242,6 +242,8 @@ static const char* construct_prompt(); ...@@ -242,6 +242,8 @@ static const char* construct_prompt();
static char *get_arg(char *line, my_bool get_next_arg); static char *get_arg(char *line, my_bool get_next_arg);
static void init_username(); static void init_username();
static void add_int_to_prompt(int toadd); static void add_int_to_prompt(int toadd);
static int normalize_dbname(const char *line, char *buff, uint buff_size);
static int get_quote_count(const char *line);
/* A structure which contains information on the commands this program /* A structure which contains information on the commands this program
can understand. */ can understand. */
...@@ -4112,8 +4114,23 @@ com_use(String *buffer __attribute__((unused)), char *line) ...@@ -4112,8 +4114,23 @@ com_use(String *buffer __attribute__((unused)), char *line)
int select_db; int select_db;
bzero(buff, sizeof(buff)); bzero(buff, sizeof(buff));
strmake(buff, line, sizeof(buff) - 1);
tmp= get_arg(buff, 0); /*
In case number of quotes exceed 2, we try to get
the normalized db name.
*/
if (get_quote_count(line) > 2)
{
if (normalize_dbname(line, buff, sizeof(buff)))
return put_error(&mysql);
tmp= buff;
}
else
{
strmake(buff, line, sizeof(buff) - 1);
tmp= get_arg(buff, 0);
}
if (!tmp || !*tmp) if (!tmp || !*tmp)
{ {
put_info("USE must be followed by a database name", INFO_ERROR); put_info("USE must be followed by a database name", INFO_ERROR);
...@@ -4179,6 +4196,62 @@ com_use(String *buffer __attribute__((unused)), char *line) ...@@ -4179,6 +4196,62 @@ com_use(String *buffer __attribute__((unused)), char *line)
return 0; return 0;
} }
/**
Normalize database name.
@param line [IN] The command.
@param buff [OUT] Normalized db name.
@param buff_size [IN] Buffer size.
@return Operation status
@retval 0 Success
@retval 1 Failure
@note Sometimes server normilizes the database names
& APIs like mysql_select_db() expect normalized
database names. Since it is difficult to perform
the name conversion/normalization on the client
side, this function tries to get the normalized
dbname (indirectly) from the server.
*/
static int
normalize_dbname(const char *line, char *buff, uint buff_size)
{
MYSQL_RES *res= NULL;
/* Send the "USE db" commmand to the server. */
if (mysql_query(&mysql, line))
return 1;
/*
Now, get the normalized database name and store it
into the buff.
*/
if (!mysql_query(&mysql, "SELECT DATABASE()") &&
(res= mysql_use_result(&mysql)))
{
MYSQL_ROW row= mysql_fetch_row(res);
if (row && row[0])
{
size_t len= strlen(row[0]);
/* Make sure there is enough room to store the dbname. */
if ((len > buff_size) || ! memcpy(buff, row[0], len))
{
mysql_free_result(res);
return 1;
}
}
mysql_free_result(res);
}
/* Restore the original database. */
if (current_db && mysql_select_db(&mysql, current_db))
return 1;
return 0;
}
static int static int
com_warnings(String *buffer __attribute__((unused)), com_warnings(String *buffer __attribute__((unused)),
char *line __attribute__((unused))) char *line __attribute__((unused)))
...@@ -4258,6 +4331,20 @@ char *get_arg(char *line, my_bool get_next_arg) ...@@ -4258,6 +4331,20 @@ char *get_arg(char *line, my_bool get_next_arg)
return valid_arg ? start : NullS; return valid_arg ? start : NullS;
} }
/*
Number of quotes present in the command's argument.
*/
static int
get_quote_count(const char *line)
{
int quote_count;
const char *ptr= line;
for(quote_count= 0; ptr ++ && *ptr; ptr= strpbrk(ptr, "\"\'`"))
quote_count ++;
return quote_count;
}
static int static int
sql_real_connect(char *host,char *database,char *user,char *password, sql_real_connect(char *host,char *database,char *user,char *password,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment