Commit 7d7a248d authored by monty@mashka.mysql.fi's avatar monty@mashka.mysql.fi

Merge work:/home/bk/mysql-4.1 into mashka.mysql.fi:/home/my/mysql-4.1

parents 474d0136 acf89934
......@@ -597,3 +597,4 @@ vio/test-sslclient
vio/test-sslserver
vio/viotest-ssl
scripts/fill_help_tables.sql
scripts/fill_help_tables
......@@ -991,7 +991,8 @@ int do_sync_with_master2(const char* p)
mysql_errno(mysql), mysql_error(mysql));
if (!(last_result = res = mysql_store_result(mysql)))
die("line %u: mysql_store_result() returned NULL", start_lineno);
die("line %u: mysql_store_result() returned NULL for '%s'", start_lineno,
query_buf);
if (!(row = mysql_fetch_row(res)))
die("line %u: empty result in %s", start_lineno, query_buf);
if (!row[0])
......@@ -1021,17 +1022,19 @@ int do_save_master_pos()
MYSQL_RES* res;
MYSQL_ROW row;
MYSQL* mysql = &cur_con->mysql;
const char *query;
int rpl_parse;
rpl_parse = mysql_rpl_parse_enabled(mysql);
mysql_disable_rpl_parse(mysql);
if (mysql_query(mysql, "show master status"))
if (mysql_query(mysql, query= "show master status"))
die("At line %u: failed in show master status: %d: %s", start_lineno,
mysql_errno(mysql), mysql_error(mysql));
if (!(last_result =res = mysql_store_result(mysql)))
die("line %u: mysql_store_result() retuned NULL", start_lineno);
die("line %u: mysql_store_result() retuned NULL for '%s'", start_lineno,
query);
if (!(row = mysql_fetch_row(res)))
die("line %u: empty result in show master status", start_lineno);
strnmov(master_pos.file, row[0], sizeof(master_pos.file)-1);
......
......@@ -215,30 +215,31 @@ my_bool my_connect(my_socket s, const struct sockaddr *name,
if (res == 0) /* Connected quickly! */
return(0);
/* Otherwise, our connection is "in progress." We can use
* the select() call to wait up to a specified period of time
* for the connection to suceed. If select() returns 0
* (after waiting howevermany seconds), our socket never became
* writable (host is probably unreachable.) Otherwise, if
* select() returns 1, then one of two conditions exist:
*
* 1. An error occured. We use getsockopt() to check for this.
* 2. The connection was set up sucessfully: getsockopt() will
* return 0 as an error.
*
* Thanks goes to Andrew Gierth <andrew@erlenstar.demon.co.uk>
* who posted this method of timing out a connect() in
* comp.unix.programmer on August 15th, 1997.
/*
Otherwise, our connection is "in progress." We can use
the select() call to wait up to a specified period of time
for the connection to succeed. If select() returns 0
(after waiting howevermany seconds), our socket never became
writable (host is probably unreachable.) Otherwise, if
select() returns 1, then one of two conditions exist:
1. An error occured. We use getsockopt() to check for this.
2. The connection was set up sucessfully: getsockopt() will
return 0 as an error.
Thanks goes to Andrew Gierth <andrew@erlenstar.demon.co.uk>
who posted this method of timing out a connect() in
comp.unix.programmer on August 15th, 1997.
*/
FD_ZERO(&sfds);
FD_SET(s, &sfds);
/*
* select could be interrupted by a signal, and if it is,
* the timeout should be adjusted and the select restarted
* to work around OSes that don't restart select and
* implementations of select that don't adjust tv upon
* failure to reflect the time remaining
select could be interrupted by a signal, and if it is,
the timeout should be adjusted and the select restarted
to work around OSes that don't restart select and
implementations of select that don't adjust tv upon
failure to reflect the time remaining
*/
start_time = time(NULL);
for (;;)
......@@ -258,9 +259,10 @@ my_bool my_connect(my_socket s, const struct sockaddr *name,
return 1;
}
/* select() returned something more interesting than zero, let's
* see if we have any errors. If the next two statements pass,
* we've got an open socket!
/*
select() returned something more interesting than zero, let's
see if we have any errors. If the next two statements pass,
we've got an open socket!
*/
s_err=0;
......@@ -276,6 +278,7 @@ my_bool my_connect(my_socket s, const struct sockaddr *name,
#endif
}
/*
Create a named pipe connection
*/
......@@ -348,6 +351,7 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
}
#endif
/*
Create new shared memory connection, return handler of connection
......@@ -357,6 +361,7 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
net Pointer of net structure
connect_timeout Timeout of connection
*/
#ifdef HAVE_SMEM
HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout)
{
......@@ -401,58 +406,60 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout)
*/
suffix_pos = strxmov(tmp,shared_memory_base_name,"_",NullS);
strmov(suffix_pos, "CONNECT_REQUEST");
if ((event_connect_request = OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp)) == NULL)
if (!(event_connect_request= OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp)))
{
error_allow = CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR;
goto err;
}
strmov(suffix_pos, "CONNECT_ANSWER");
if ((event_connect_answer = OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp)) == NULL)
if (!(event_connect_answer= OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp)))
{
error_allow = CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR;
goto err;
}
strmov(suffix_pos, "CONNECT_DATA");
if ((handle_connect_file_map = OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)) == NULL)
if (!(handle_connect_file_map= OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)))
{
error_allow = CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR;
goto err;
}
if ((handle_connect_map = MapViewOfFile(handle_connect_file_map,FILE_MAP_WRITE,0,0,sizeof(DWORD))) == NULL)
if (!(handle_connect_map= MapViewOfFile(handle_connect_file_map,
FILE_MAP_WRITE,0,0,sizeof(DWORD))))
{
error_allow = CR_SHARED_MEMORY_CONNECT_MAP_ERROR;
goto err;
}
/*
/*
Send to server request of connection
*/
*/
if (!SetEvent(event_connect_request))
{
error_allow = CR_SHARED_MEMORY_CONNECT_SET_ERROR;
goto err;
}
/*
/*
Wait of answer from server
*/
if (WaitForSingleObject(event_connect_answer,connect_timeout*1000) != WAIT_OBJECT_0)
*/
if (WaitForSingleObject(event_connect_answer,connect_timeout*1000) !=
WAIT_OBJECT_0)
{
error_allow = CR_SHARED_MEMORY_CONNECT_ABANDODED_ERROR;
goto err;
}
/*
/*
Get number of connection
*/
*/
connect_number = uint4korr(handle_connect_map);/*WAX2*/
p = int2str(connect_number, connect_number_char, 10);
p= int2str(connect_number, connect_number_char, 10);
/*
/*
The name of event and file-mapping events create agree next rule:
shared_memory_base_name+unique_part+number_of_connection
Where:
shared_memory_base_name is uniquel value for each server
unique_part is uniquel value for each object (events and file-mapping)
number_of_connection is number of connection between server and client
*/
*/
suffix_pos = strxmov(tmp,shared_memory_base_name,"_",connect_number_char,
"_",NullS);
strmov(suffix_pos, "DATA");
......@@ -495,33 +502,46 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout)
error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
goto err2;
}
/*
/*
Set event that server should send data
*/
*/
SetEvent(event_server_read);
err2:
if (error_allow == 0)
{
net->vio = vio_new_win32shared_memory(net,handle_file_map,handle_map,event_server_wrote,
event_server_read,event_client_wrote,event_client_read);
net->vio= vio_new_win32shared_memory(net,handle_file_map,handle_map,
event_server_wrote,
event_server_read,event_client_wrote,
event_client_read);
}
else
{
error_code = GetLastError();
if (event_server_read) CloseHandle(event_server_read);
if (event_server_wrote) CloseHandle(event_server_wrote);
if (event_client_read) CloseHandle(event_client_read);
if (event_client_wrote) CloseHandle(event_client_wrote);
if (handle_map) UnmapViewOfFile(handle_map);
if (handle_file_map) CloseHandle(handle_file_map);
if (event_server_read)
CloseHandle(event_server_read);
if (event_server_wrote)
CloseHandle(event_server_wrote);
if (event_client_read)
CloseHandle(event_client_read);
if (event_client_wrote)
CloseHandle(event_client_wrote);
if (handle_map)
UnmapViewOfFile(handle_map);
if (handle_file_map)
CloseHandle(handle_file_map);
}
err:
if (error_allow) error_code = GetLastError();
if (event_connect_request) CloseHandle(event_connect_request);
if (event_connect_answer) CloseHandle(event_connect_answer);
if (handle_connect_map) UnmapViewOfFile(handle_connect_map);
if (handle_connect_file_map) CloseHandle(handle_connect_file_map);
if (error_allow)
error_code = GetLastError();
if (event_connect_request)
CloseHandle(event_connect_request);
if (event_connect_answer)
CloseHandle(event_connect_answer);
if (handle_connect_map)
UnmapViewOfFile(handle_connect_map);
if (handle_connect_file_map)
CloseHandle(handle_connect_file_map);
if (error_allow)
{
net->last_errno=error_allow;
......@@ -532,11 +552,12 @@ err:
return(INVALID_HANDLE_VALUE);
}
return(handle_map);
};
}
#endif
/*****************************************************************************
read a packet from server. Give error message if socket was down
Read a packet from server. Give error message if socket was down
or packet is an error message
*****************************************************************************/
......@@ -1796,10 +1817,11 @@ void STDCALL mysql_once_init(void)
#endif
}
/**************************************************************************
/*
Fill in SSL part of MYSQL structure and set 'use_ssl' flag.
NB! Errors are not reported until you do mysql_real_connect.
**************************************************************************/
*/
#define strdup_if_not_null(A) (A) == 0 ? 0 : my_strdup((A),MYF(MY_WME))
......@@ -1822,10 +1844,10 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
}
/**************************************************************************
/*
Free strings in the SSL structure and clear 'use_ssl' flag.
NB! Errors are not reported until you do mysql_real_connect.
**************************************************************************/
*/
#ifdef HAVE_OPENSSL
static void
......@@ -1847,6 +1869,75 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
}
#endif /* HAVE_OPENSSL */
/*
Handle password authentication
*/
static my_bool mysql_autenticate(MYSQL *mysql, const char *passwd)
{
ulong pkt_length;
NET *net= &mysql->net;
char buff[SCRAMBLE41_LENGTH];
char password_hash[SCRAMBLE41_LENGTH]; /* Used for storage of stage1 hash */
/* We shall only query server if it expect us to do so */
if ((pkt_length=net_safe_read(mysql)) == packet_error)
goto error;
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
/*
This should always happen with new server unless empty password
OK/Error packets have zero as the first char
*/
if (pkt_length == 24 && net->read_pos[0])
{
/* Old passwords will have '*' at the first byte of hash */
if (net->read_pos[0] != '*')
{
/* Build full password hash as it is required to decode scramble */
password_hash_stage1(buff, passwd);
/* Store copy as we'll need it later */
memcpy(password_hash,buff,SCRAMBLE41_LENGTH);
/* Finally hash complete password using hash we got from server */
password_hash_stage2(password_hash,(const char*) net->read_pos);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((const char*) net->read_pos+4,mysql->scramble_buff,
password_hash, SCRAMBLE41_LENGTH);
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
/* Encode scramble with password. Recycle buffer */
password_crypt(mysql->scramble_buff,buff,buff,SCRAMBLE41_LENGTH);
}
else
{
/* Create password to decode scramble */
create_key_from_old_password(passwd,password_hash);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((const char*) net->read_pos+4,mysql->scramble_buff,
password_hash, SCRAMBLE41_LENGTH);
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
/* Finally scramble decoded scramble with password */
scramble(buff, mysql->scramble_buff, passwd,0);
}
/* Write second package of authentication */
if (my_net_write(net,buff,SCRAMBLE41_LENGTH) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Read what server thinks about out new auth message report */
if (net_safe_read(mysql) == packet_error)
goto error;
}
}
return 0;
error:
return 1;
}
/**************************************************************************
Connect to sql server
If host == 0 then use localhost
......@@ -1884,7 +1975,6 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
{
char buff[NAME_LEN+USERNAME_LENGTH+100],charset_name_buff[16];
char *end,*host_info,*charset_name;
char password_hash[SCRAMBLE41_LENGTH]; /* tmp storage stage1 hash */
my_socket sock;
uint32 ip_addr;
struct sockaddr_in sock_addr;
......@@ -1930,7 +2020,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
passwd=mysql->options.password;
#ifndef DONT_USE_MYSQL_PWD
if (!passwd)
passwd=getenv("MYSQL_PWD"); /* get it from environment (haneke) */
passwd=getenv("MYSQL_PWD"); /* get it from environment */
#endif
}
if (!db || !db[0])
......@@ -1944,10 +2034,11 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
/*
** Grab a socket and connect it to the server
Grab a socket and connect it to the server
*/
#if defined(HAVE_SMEM)
if ((!mysql->options.protocol || mysql->options.protocol == MYSQL_PROTOCOL_MEMORY)&&
if ((!mysql->options.protocol ||
mysql->options.protocol == MYSQL_PROTOCOL_MEMORY) &&
(!host || !strcmp(host,LOCAL_HOST)))
{
if ((create_shared_memory(mysql,net, mysql->options.connect_timeout)) ==
......@@ -1961,9 +2052,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
(int) have_tcpip));
if (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY)
goto error;
/*
Try also with PIPE or TCP/IP
*/
/* Try also with PIPE or TCP/IP */
}
else
{
......@@ -1974,10 +2063,12 @@ Try also with PIPE or TCP/IP
host_info=(char*) ER(CR_SHARED_MEMORY_CONNECTION);
}
} else
#endif //HAVE_SMEM
#endif /* HAVE_SMEM */
#if defined(HAVE_SYS_UN_H)
if ((!mysql->options.protocol || mysql->options.protocol == MYSQL_PROTOCOL_SOCKET)&&
(!host || !strcmp(host,LOCAL_HOST)) && (unix_socket || mysql_unix_port))
if ((!mysql->options.protocol ||
mysql->options.protocol == MYSQL_PROTOCOL_SOCKET)&&
(!host || !strcmp(host,LOCAL_HOST)) &&
(unix_socket || mysql_unix_port))
{
host=LOCAL_HOST;
if (!unix_socket)
......@@ -1997,7 +2088,8 @@ Try also with PIPE or TCP/IP
if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
mysql->options.connect_timeout))
{
DBUG_PRINT("error",("Got error %d on connect to local server",socket_errno));
DBUG_PRINT("error",("Got error %d on connect to local server",
socket_errno));
net->last_errno=CR_CONNECTION_ERROR;
sprintf(net->last_error,ER(net->last_errno),unix_socket,socket_errno);
goto error;
......@@ -2007,9 +2099,12 @@ Try also with PIPE or TCP/IP
}
else
#elif defined(__WIN__)
if ((!mysql->options.protocol || mysql->options.protocol == MYSQL_PROTOCOL_PIPE)&&
{
if ((!mysql->options.protocol ||
mysql->options.protocol == MYSQL_PROTOCOL_PIPE)&&
((unix_socket || !host && is_NT() ||
host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||!have_tcpip))&&(!net->vio))
host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||! have_tcpip))&&
(!net->vio))
{
sock=0;
if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
......@@ -2025,9 +2120,7 @@ Try also with PIPE or TCP/IP
(host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
(unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
goto error;
/*
Try also with TCP/IP
*/
/* Try also with TCP/IP */
}
else
{
......@@ -2036,8 +2129,10 @@ Try also with PIPE or TCP/IP
unix_socket);
}
}
}
#endif
if ((!mysql->options.protocol || mysql->options.protocol == MYSQL_PROTOCOL_TCP)&&(!net->vio))
if ((!mysql->options.protocol ||
mysql->options.protocol == MYSQL_PROTOCOL_TCP)&&(!net->vio))
{
unix_socket=0; /* This is not used */
if (!port)
......@@ -2058,7 +2153,7 @@ Try also with PIPE or TCP/IP
sock_addr.sin_family = AF_INET;
/*
** The server name may be a host name or IP address
The server name may be a host name or IP address
*/
if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE)
......@@ -2086,20 +2181,20 @@ Try also with PIPE or TCP/IP
if (my_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
mysql->options.connect_timeout))
{
DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,host));
DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,
host));
net->last_errno= CR_CONN_HOST_ERROR;
sprintf(net->last_error ,ER(CR_CONN_HOST_ERROR), host, socket_errno);
goto error;
}
}
else
if (!net->vio)
else if (!net->vio)
{
DBUG_PRINT("error",("Unknow protocol %d ",mysql->options.protocol));
net->last_errno= CR_CONN_UNKNOW_PROTOCOL;
sprintf(net->last_error ,ER(CR_CONN_UNKNOW_PROTOCOL));
goto error;
};
}
if (!net->vio || my_net_init(net, net->vio))
{
......@@ -2167,7 +2262,6 @@ Try also with PIPE or TCP/IP
if (!(mysql->charset =
get_charset((uint8) mysql->server_language, MYF(0))))
mysql->charset = default_charset_info; /* shouldn't be fatal */
}
else
mysql->charset=default_charset_info;
......@@ -2349,59 +2443,9 @@ Try also with PIPE or TCP/IP
goto error;
}
/* We shall only query sever if it expect us to do so */
if ( (pkt_length=net_safe_read(mysql)) == packet_error)
if (mysql_autenticate(mysql, passwd))
goto error;
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
/* This should always happen with new server unless empty password */
if (pkt_length==24 && net->read_pos[0])
/* OK/Error packets have zero as the first char */
{
/* Old passwords will have '*' at the first byte of hash */
if (net->read_pos[0] != '*')
{
/* Build full password hash as it is required to decode scramble */
password_hash_stage1(buff, passwd);
/* Store copy as we'll need it later */
memcpy(password_hash,buff,SCRAMBLE41_LENGTH);
/* Finally hash complete password using hash we got from server */
password_hash_stage2(password_hash,(const char*) net->read_pos);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((const char*) net->read_pos+4,mysql->scramble_buff,
password_hash, SCRAMBLE41_LENGTH);
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
/* Encode scramble with password. Recycle buffer */
password_crypt(mysql->scramble_buff,buff,buff,SCRAMBLE41_LENGTH);
}
else
{
/* Create password to decode scramble */
create_key_from_old_password(passwd,password_hash);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((const char*) net->read_pos+4,mysql->scramble_buff,
password_hash, SCRAMBLE41_LENGTH);
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
/* Finally scramble decoded scramble with password */
scramble(buff, mysql->scramble_buff, passwd,0);
}
/* Write second package of authentication */
if (my_net_write(net,buff,SCRAMBLE41_LENGTH) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Read What server thinks about out new auth message report */
if (net_safe_read(mysql) == packet_error)
goto error;
}
}
/* End of authentication part of handshake */
if (client_flag & CLIENT_COMPRESS) /* We will use compression */
net->compress=1;
if (mysql->options.max_allowed_packet)
......@@ -2521,10 +2565,6 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
const char *passwd, const char *db)
{
char buff[512],*end=buff;
ulong pkt_length;
char password_hash[SCRAMBLE41_LENGTH]; /* Used for tmp storage of stage1 hash */
NET *net= &mysql->net;
DBUG_ENTER("mysql_change_user");
if (!user)
......@@ -2553,83 +2593,36 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
*end=0; /* Store zero length scramble */
}
else
{
/*
Real scramble is only sent to old servers. This can be blocked
by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1);
*/
end=scramble(end, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
}
/* Add database if needed */
end=strmov(end+1,db ? db : "");
/* Write authentication package */
simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1);
/* We shall only query sever if it expect us to do so */
if ( (pkt_length=net_safe_read(mysql)) == packet_error)
if (mysql_autenticate(mysql, passwd))
goto error;
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
/* This should always happen with new server unless empty password */
if (pkt_length==24 && net->read_pos[0])
/* Err/OK messages has first character=0 */
{
/* Old passwords will have zero at the first byte of hash */
if (net->read_pos[0] != '*')
{
/* Build full password hash as it is required to decode scramble */
password_hash_stage1(buff, passwd);
/* Store copy as we'll need it later */
memcpy(password_hash,buff,SCRAMBLE41_LENGTH);
/* Finally hash complete password using hash we got from server */
password_hash_stage2(password_hash, (const char*) net->read_pos);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((const char*) net->read_pos+4, mysql->scramble_buff,
password_hash, SCRAMBLE41_LENGTH);
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
/* Encode scramble with password. Recycle buffer */
password_crypt(mysql->scramble_buff,buff,buff,SCRAMBLE41_LENGTH);
}
else
{
/* Create password to decode scramble */
create_key_from_old_password(passwd,password_hash);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((const char*) net->read_pos+4,mysql->scramble_buff,
password_hash, SCRAMBLE41_LENGTH);
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
/* Finally scramble decoded scramble with password */
scramble(buff, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
}
/* Write second package of authentication */
if (my_net_write(net,buff,SCRAMBLE41_LENGTH) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Read What server thinks about out new auth message report */
if (net_safe_read(mysql) == packet_error)
goto error;
}
}
/* Free old connect information */
my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
/* alloc new connect information */
mysql->user= my_strdup(user,MYF(MY_WME));
mysql->passwd=my_strdup(passwd,MYF(MY_WME));
mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0;
DBUG_RETURN(0);
error:
error:
DBUG_RETURN(1);
}
......@@ -5102,6 +5095,7 @@ static void fetch_result_datetime(MYSQL_BIND *param, uchar **row)
*row+= read_binary_datetime(tm, row);
}
static void fetch_result_str(MYSQL_BIND *param, uchar **row)
{
ulong length= net_field_length(row);
......@@ -5110,7 +5104,7 @@ static void fetch_result_str(MYSQL_BIND *param, uchar **row)
/* Add an end null if there is room in the buffer */
if (copy_length != param->buffer_length)
*(param->buffer+copy_length)= '\0';
*param->length= length; // return total length
*param->length= length; /* return total length */
*row+= length;
}
......
......@@ -373,12 +373,21 @@ bool Protocol::send_fields(List<Item> *list, uint flag)
Send_field server_field;
item->make_field(&server_field);
client_field->db= strdup_root(alloc, server_field.db_name);
client_field->table= strdup_root(alloc, server_field.table_name);
client_field->name= strdup_root(alloc,server_field.col_name);
client_field->name= strdup_root(alloc, server_field.col_name);
client_field->org_table= strdup_root(alloc, server_field.org_table_name);
client_field->org_name= strdup_root(alloc, server_field.org_col_name);
client_field->length= server_field.length;
client_field->type= server_field.type;
client_field->flags= server_field.flags;
client_field->decimals= server_field.decimals;
client_field->db_length= strlen(client_field->db);
client_field->table_length= strlen(client_field->table);
client_field->name_length= strlen(client_field->name);
client_field->org_name_length= strlen(client_field->org_name);
client_field->org_table_length= strlen(client_field->org_table);
client_field->charsetnr= server_field.charsetnr;
if (INTERNAL_NUM_FIELD(client_field))
client_field->flags|= NUM_FLAG;
......
......@@ -4,9 +4,6 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
stop slave;
reset master;
drop table if exists t1;
create table t1(n char(30));
set @i1:=12345678901234, @i2:=-12345678901234, @i3:=0, @i4:=-1;
set @s1:='This is a test', @r1:=12.5, @r2:=-12.5;
......@@ -23,7 +20,6 @@ set @q:='abc';
insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2'));
set @a:=5;
insert into t1 values (@a),(@a);
start slave;
select * from t1;
n
12345678901234
......@@ -59,20 +55,20 @@ slave-bin.000001 396 User var 2 396 @r1=12.5
slave-bin.000001 439 User var 2 439 @r2=-12.5
slave-bin.000001 482 Query 1 482 use `test`; insert into t1 values (@r1), (@r2)
slave-bin.000001 551 User var 2 551 @s1='This is a test'
slave-bin.000001 601 User var 2 601 @s2=''
slave-bin.000001 637 User var 2 637 @s3='abc'def'
slave-bin.000001 680 User var 2 680 @s4='abc\def'
slave-bin.000001 723 User var 2 723 @s5='abc'def'
slave-bin.000001 766 Query 1 766 use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5)
slave-bin.000001 856 User var 2 856 @n1=NULL
slave-bin.000001 882 Query 1 882 use `test`; insert into t1 values (@n1)
slave-bin.000001 944 Query 1 944 use `test`; insert into t1 values (@n2)
slave-bin.000001 1006 Query 1 1006 use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1)
slave-bin.000001 1094 User var 2 1094 @a='2'
slave-bin.000001 1130 Query 1 1130 use `test`; insert into t1 values (@a+(@b:=@a+1))
slave-bin.000001 1202 User var 2 1202 @q='abc'
slave-bin.000001 1240 Query 1 1240 use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2'))
slave-bin.000001 1344 User var 2 1344 @a=5
slave-bin.000001 1386 Query 1 1386 use `test`; insert into t1 values (@a),(@a)
slave-bin.000001 600 User var 2 600 @s2=''
slave-bin.000001 635 User var 2 635 @s3='abc'def'
slave-bin.000001 677 User var 2 677 @s4='abc\def'
slave-bin.000001 719 User var 2 719 @s5='abc'def'
slave-bin.000001 761 Query 1 761 use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5)
slave-bin.000001 851 User var 2 851 @n1=NULL
slave-bin.000001 877 Query 1 877 use `test`; insert into t1 values (@n1)
slave-bin.000001 939 Query 1 939 use `test`; insert into t1 values (@n2)
slave-bin.000001 1001 Query 1 1001 use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1)
slave-bin.000001 1089 User var 2 1089 @a='2'
slave-bin.000001 1124 Query 1 1124 use `test`; insert into t1 values (@a+(@b:=@a+1))
slave-bin.000001 1196 User var 2 1196 @q='abc'
slave-bin.000001 1233 Query 1 1233 use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2'))
slave-bin.000001 1337 User var 2 1337 @a=5
slave-bin.000001 1379 Query 1 1379 use `test`; insert into t1 values (@a),(@a)
drop table t1;
stop slave;
......@@ -130,6 +130,10 @@ select d from t1 having d like "%HELLO%";
d
HELLO
HELLO MY
select d from t1 having d like "%HE%LLO%";
d
HELLO
HELLO MY
select t from t1 order by t;
t
NULL
......
#
# Test of replicating user variables
#
source include/master-slave.inc;
connection master;
save_master_pos;
connection slave;
sync_with_master;
stop slave;
reset master;
connection master;
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1(n char(30));
set @i1:=12345678901234, @i2:=-12345678901234, @i3:=0, @i4:=-1;
set @s1:='This is a test', @r1:=12.5, @r2:=-12.5;
......@@ -27,7 +21,6 @@ set @a:=5;
insert into t1 values (@a),(@a);
save_master_pos;
connection slave;
start slave;
sync_with_master;
select * from t1;
show binlog events from 141;
......
......@@ -87,6 +87,7 @@ select b from t1 where b like "%HELLO%";
select d from t1 where d like "%HELLO%";
select c from t1 having c like "%HELLO%";
select d from t1 having d like "%HELLO%";
select d from t1 having d like "%HE%LLO%";
select t from t1 order by t;
select c from t1 order by c;
select b from t1 order by b;
......
......@@ -1203,18 +1203,22 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
max_length= (*ref)->max_length;
maybe_null= (*ref)->maybe_null;
decimals= (*ref)->decimals;
set_charset((*ref)->charset());
fixed= 1;
if (ref && (*ref)->check_cols(1))
return 1;
return 0;
}
bool Item_default_value::eq(const Item *item, bool binary_cmp) const
{
return item->type() == DEFAULT_VALUE_ITEM &&
((Item_default_value *)item)->arg->eq(arg, binary_cmp);
}
bool Item_default_value::fix_fields(THD *thd, struct st_table_list *table_list, Item **items)
{
if (!arg)
......
......@@ -1129,11 +1129,16 @@ void in_string::set(uint pos,Item *item)
String *res=item->val_str(str);
if (res && res != str)
*str= *res;
// BAR TODO: I'm not sure this is absolutely correct
if (!str->charset())
str->set_charset(default_charset_info);
{
CHARSET_INFO *cs;
if (!(cs= item->charset()))
cs= default_charset_info; // Should never happen for STR items
str->set_charset(cs);
}
}
byte *in_string::get_value(Item *item)
{
return (byte*) item->val_str(&tmp);
......@@ -1692,6 +1697,7 @@ longlong Item_func_isnull::val_int()
return args[0]->is_null() ? 1: 0;
}
longlong Item_func_isnotnull::val_int()
{
return args[0]->is_null() ? 0 : 1;
......@@ -1713,9 +1719,6 @@ longlong Item_func_like::val_int()
return 0;
}
null_value=0;
if ((res->charset()->state & MY_CS_BINSORT) ||
(res2->charset()->state & MY_CS_BINSORT))
set_charset(&my_charset_bin);
if (canDoTurboBM)
return turboBM_matches(res->ptr(), res->length()) ? 1 : 0;
return my_wildcmp(charset(),
......@@ -1748,10 +1751,19 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
return 1;
/*
TODO--we could do it for non-const, but we'd have to
recompute the tables for each row--probably not worth it.
Comparision is by default done according to character set of LIKE
*/
if (binary_cmp)
set_charset(&my_charset_bin);
else
set_charset(args[1]->charset());
/*
We could also do boyer-more for non-const items, but as we would have to
recompute the tables for each row it's not worth it.
*/
if (args[1]->const_item() && !(specialflag & SPECIAL_NO_NEW_FUNC))
if (args[1]->const_item() && !use_strnxfrm(charset()) &&
!(specialflag & SPECIAL_NO_NEW_FUNC))
{
String* res2 = args[1]->val_str(&tmp_value2);
if (!res2)
......
......@@ -2083,7 +2083,8 @@ longlong
Item_func_set_user_var::val_int()
{
longlong value=args[0]->val_int();
update_hash((void*) &value,sizeof(longlong),INT_RESULT, default_charset_info);
update_hash((void*) &value, sizeof(longlong), INT_RESULT,
default_charset_info);
return value;
}
......@@ -2092,9 +2093,10 @@ Item_func_set_user_var::val_str(String *str)
{
String *res=args[0]->val_str(str);
if (!res) // Null value
update_hash((void*) 0, 0, STRING_RESULT, default_charset_info);
update_hash((void*) 0, 0, STRING_RESULT, &my_charset_bin);
else
update_hash(res->c_ptr(),res->length()+1,STRING_RESULT,res->charset());
update_hash((void*) res->ptr(), res->length(), STRING_RESULT,
res->charset());
return res;
}
......@@ -2129,13 +2131,13 @@ Item_func_get_user_var::val_str(String *str)
return NULL;
switch (entry->type) {
case REAL_RESULT:
str->set(*(double*) entry->value,decimals,thd_charset());
str->set(*(double*) entry->value,decimals, &my_charset_bin);
break;
case INT_RESULT:
str->set(*(longlong*) entry->value,thd_charset());
str->set(*(longlong*) entry->value, &my_charset_bin);
break;
case STRING_RESULT:
if (str->copy(entry->value, entry->length-1, entry->var_charset))
if (str->copy(entry->value, entry->length, entry->var_charset))
{
null_value=1;
return NULL;
......@@ -2191,8 +2193,6 @@ longlong Item_func_get_user_var::val_int()
return LL(0); // Impossible
}
/* From sql_parse.cc */
extern bool is_update_query(enum enum_sql_command command);
void Item_func_get_user_var::fix_length_and_dec()
{
......@@ -2207,13 +2207,15 @@ void Item_func_get_user_var::fix_length_and_dec()
if (opt_bin_log && is_update_query(thd->lex.sql_command) &&
var_entry->used_query_id != thd->query_id)
{
uint size;
/*
First we need to store value of var_entry, when the next situation appers:
First we need to store value of var_entry, when the next situation
appers:
> set @a:=1;
> insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1);
We have to write to binlog value @a= 1;
*/
uint size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length;
size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length;
if (!(user_var_event= (BINLOG_USER_VAR_EVENT *) thd->alloc(size)))
goto err;
......@@ -2240,6 +2242,7 @@ void Item_func_get_user_var::fix_length_and_dec()
}
}
return;
err:
thd->fatal_error();
return;
......@@ -2247,7 +2250,9 @@ err:
bool Item_func_get_user_var::const_item() const
{ return var_entry && current_thd->query_id != var_entry->update_query_id; }
{
return var_entry && current_thd->query_id != var_entry->update_query_id;
}
enum Item_result Item_func_get_user_var::result_type() const
......@@ -2275,14 +2280,9 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const
if (this == item)
return 1; // Same item is same.
/* Check if other type is also a get_user_var() object */
#ifdef FIX_THIS
if (item->eq == &Item_func_get_user_var::eq)
return 0;
#else
if (item->type() != FUNC_ITEM ||
((Item_func*) item)->func_name() != func_name())
return 0;
#endif
Item_func_get_user_var *other=(Item_func_get_user_var*) item;
return (name.length == other->name.length &&
!memcmp(name.str, other->name.str, name.length));
......
......@@ -1899,19 +1899,10 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
#endif
/*****************************************************************************
*****************************************************************************
/****************************************************************************
Rand_log_event methods
****************************************************************************/
*****************************************************************************
****************************************************************************/
/*****************************************************************************
Rand_log_event::pack_info()
****************************************************************************/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
void Rand_log_event::pack_info(Protocol *protocol)
{
......@@ -1924,11 +1915,7 @@ void Rand_log_event::pack_info(Protocol *protocol)
}
#endif
/*****************************************************************************
Rand_log_event::Rand_log_event()
****************************************************************************/
Rand_log_event::Rand_log_event(const char* buf, bool old_format)
:Log_event(buf, old_format)
{
......@@ -1937,11 +1924,7 @@ Rand_log_event::Rand_log_event(const char* buf, bool old_format)
seed2 = uint8korr(buf+RAND_SEED2_OFFSET);
}
/*****************************************************************************
Rand_log_event::write_data()
****************************************************************************/
int Rand_log_event::write_data(IO_CACHE* file)
{
char buf[16];
......@@ -1950,11 +1933,7 @@ int Rand_log_event::write_data(IO_CACHE* file)
return my_b_safe_write(file, (byte*) buf, sizeof(buf));
}
/*****************************************************************************
Rand_log_event::print()
****************************************************************************/
#ifdef MYSQL_CLIENT
void Rand_log_event::print(FILE* file, bool short_form, char* last_db)
{
......@@ -1970,11 +1949,7 @@ void Rand_log_event::print(FILE* file, bool short_form, char* last_db)
}
#endif // MYSQL_CLIENT
/*****************************************************************************
Rand_log_event::exec_event()
****************************************************************************/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Rand_log_event::exec_event(struct st_relay_log_info* rli)
{
......@@ -1986,19 +1961,10 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli)
#endif // !MYSQL_CLIENT
/*****************************************************************************
*****************************************************************************
/***************************************************************************
User_var_log_event methods
***************************************************************************/
*****************************************************************************
****************************************************************************/
/*****************************************************************************
User_var_log_event::pack_info()
****************************************************************************/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
void User_var_log_event::pack_info(Protocol* protocol)
{
......@@ -2019,7 +1985,7 @@ void User_var_log_event::pack_info(Protocol* protocol)
double real_val;
float8get(real_val, val);
buf= my_malloc(val_offset + FLOATING_POINT_BUFFER, MYF(MY_WME));
event_len += my_sprintf(buf + val_offset,
event_len+= my_sprintf(buf + val_offset,
(buf + val_offset, "%.14g", real_val));
break;
case INT_RESULT:
......@@ -2032,11 +1998,11 @@ void User_var_log_event::pack_info(Protocol* protocol)
only. But be carefull this is may be incorrect in other cases as
string may contain \ and '.
*/
buf= my_malloc(val_offset + 2 + val_len, MYF(MY_WME));
event_len= val_offset + 2 + val_len;
buf= my_malloc(event_len, MYF(MY_WME));
buf[val_offset]= '\'';
memcpy(buf + val_offset + 1, val, val_len);
buf[val_offset + val_len]= '\'';
event_len= val_offset + 1 + val_len;
buf[val_offset + val_len + 1]= '\'';
break;
case ROW_RESULT:
DBUG_ASSERT(1);
......@@ -2050,18 +2016,16 @@ void User_var_log_event::pack_info(Protocol* protocol)
my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
User_var_log_event::User_var_log_event()
****************************************************************************/
User_var_log_event::User_var_log_event(const char* buf, bool old_format)
:Log_event(buf, old_format)
{
buf+= (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
name_len= uint4korr(buf);
name= (char *) buf + UV_NAME_LEN_SIZE;
is_null= buf[UV_NAME_LEN_SIZE + name_len];
buf+= UV_NAME_LEN_SIZE + name_len;
is_null= (bool) *buf;
if (is_null)
{
type= STRING_RESULT;
......@@ -2070,22 +2034,16 @@ User_var_log_event::User_var_log_event(const char* buf, bool old_format)
}
else
{
type= (Item_result) buf[UV_VAL_IS_NULL + UV_NAME_LEN_SIZE + name_len];
charset_number= uint4korr(buf + UV_NAME_LEN_SIZE + name_len +
UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE);
val_len= uint4korr(buf + UV_NAME_LEN_SIZE + name_len +
UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
type= (Item_result) buf[UV_VAL_IS_NULL];
charset_number= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE);
val_len= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
UV_CHARSET_NUMBER_SIZE);
val= (char *) buf + UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL +
UV_VAL_TYPE_SIZE + UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE;
val= (char *) (buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE);
}
}
/*****************************************************************************
User_var_log_event::write_data()
****************************************************************************/
int User_var_log_event::write_data(IO_CACHE* file)
{
char buf[UV_NAME_LEN_SIZE];
......@@ -2224,19 +2182,9 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
#endif // !MYSQL_CLIENT
/*****************************************************************************
*****************************************************************************
/****************************************************************************
Slave_log_event methods
*****************************************************************************
****************************************************************************/
/*****************************************************************************
Slave_log_event::pack_info()
****************************************************************************/
****************************************************************************/
#ifdef HAVE_REPLICATION
#ifndef MYSQL_CLIENT
......@@ -2255,11 +2203,7 @@ void Slave_log_event::pack_info(Protocol *protocol)
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
Slave_log_event::Slave_log_event()
****************************************************************************/
#ifndef MYSQL_CLIENT
Slave_log_event::Slave_log_event(THD* thd_arg,
struct st_relay_log_info* rli)
......@@ -2296,21 +2240,13 @@ Slave_log_event::Slave_log_event(THD* thd_arg,
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
Slave_log_event dtor
****************************************************************************/
Slave_log_event::~Slave_log_event()
{
my_free(mem_pool, MYF(MY_ALLOW_ZERO_PTR));
}
/*****************************************************************************
Slave_log_event::print()
****************************************************************************/
#ifdef MYSQL_CLIENT
void Slave_log_event::print(FILE* file, bool short_form, char* last_db)
{
......@@ -2325,21 +2261,13 @@ master_log: '%s' master_pos: %s\n",
}
#endif // MYSQL_CLIENT
/*****************************************************************************
Slave_log_event::get_data_size()
****************************************************************************/
int Slave_log_event::get_data_size()
{
return master_host_len + master_log_len + 1 + SL_MASTER_HOST_OFFSET;
}
/*****************************************************************************
Slave_log_event::write_data()
****************************************************************************/
int Slave_log_event::write_data(IO_CACHE* file)
{
int8store(mem_pool + SL_MASTER_POS_OFFSET, master_pos);
......@@ -2348,11 +2276,7 @@ int Slave_log_event::write_data(IO_CACHE* file)
return my_b_safe_write(file, (byte*)mem_pool, get_data_size());
}
/*****************************************************************************
Slave_log_event::init_from_mem_pool()
****************************************************************************/
void Slave_log_event::init_from_mem_pool(int data_size)
{
master_pos = uint8korr(mem_pool + SL_MASTER_POS_OFFSET);
......@@ -2369,11 +2293,7 @@ void Slave_log_event::init_from_mem_pool(int data_size)
master_log_len = strlen(master_log);
}
/*****************************************************************************
Slave_log_event::Slave_log_event()
****************************************************************************/
Slave_log_event::Slave_log_event(const char* buf, int event_len)
:Log_event(buf,0),mem_pool(0),master_host(0)
{
......@@ -2387,11 +2307,7 @@ Slave_log_event::Slave_log_event(const char* buf, int event_len)
init_from_mem_pool(event_len);
}
/*****************************************************************************
Slave_log_event::exec_event()
****************************************************************************/
#ifndef MYSQL_CLIENT
int Slave_log_event::exec_event(struct st_relay_log_info* rli)
{
......
......@@ -635,7 +635,7 @@ public:
ulong val_len;
Item_result type;
uint charset_number;
byte is_null;
bool is_null;
#ifndef MYSQL_CLIENT
User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg,
char *val_arg, ulong val_len_arg, Item_result type_arg,
......
......@@ -830,6 +830,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
}
}
else
{
/*
Real scramble is only sent to old servers. This can be blocked
by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1);
......@@ -837,6 +838,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
}
/* Add database if needed */
if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
{
......
......@@ -346,6 +346,7 @@ int quick_rm_table(enum db_type base,const char *db,
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
bool mysql_change_db(THD *thd,const char *name);
void mysql_parse(THD *thd,char *inBuf,uint length);
bool is_update_query(enum enum_sql_command command);
void free_items(Item *item);
bool alloc_query(THD *thd, char *packet, ulong packet_length);
void mysql_init_select(LEX *lex);
......
......@@ -295,11 +295,12 @@ void
send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
{
NET *net= &thd->net;
if (net->no_send_ok || !net->vio) // hack for re-parsing queries
return;
char buff[MYSQL_ERRMSG_SIZE+10],*pos;
DBUG_ENTER("send_ok");
if (net->no_send_ok || !net->vio) // hack for re-parsing queries
DBUG_VOID_RETURN;
buff[0]=0; // No fields
pos=net_store_length(buff+1,(ulonglong) affected_rows);
pos=net_store_length(pos, (ulonglong) id);
......
......@@ -485,7 +485,7 @@ void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble)
Get master privilges for user (priviliges for all tables).
Required before connecting to MySQL
as we have 2 stage handshake now we cache user not to lookup
As we have 2 stage handshake now we cache user not to lookup
it second time. At the second stage we do not lookup user in case
we already know it;
......@@ -494,14 +494,13 @@ void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble)
ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *message,char **priv_user,
bool old_ver, USER_RESOURCES *mqh, char *prepared_scramble,
uint *cur_priv_version,ACL_USER** hint_user)
uint *cur_priv_version, ACL_USER **cached_user)
{
ulong user_access=NO_ACCESS;
*priv_user= (char*) user;
bool password_correct= 0;
int stage= (*hint_user != NULL); /* NULL passed as first stage */
int stage= (*cached_user != NULL); /* NULL passed as first stage */
ACL_USER *acl_user= NULL;
DBUG_ENTER("acl_getroot");
bzero(mqh,sizeof(USER_RESOURCES));
......@@ -512,7 +511,6 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
}
VOID(pthread_mutex_lock(&acl_cache->lock));
/*
Get possible access from user_list. This is or'ed to others not
fully specified
......@@ -520,9 +518,10 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
If we have cached user use it, in other case look it up.
*/
if (stage && (*cur_priv_version==priv_version))
acl_user=*hint_user;
if (stage && (*cur_priv_version == priv_version))
acl_user= *cached_user;
else
{
for (uint i=0 ; i < acl_users.elements ; i++)
{
ACL_USER *acl_user_search=dynamic_element(&acl_users,i,ACL_USER*);
......@@ -531,28 +530,28 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
if (compare_hostname(&acl_user_search->host,host,ip))
{
/* Found mathing user */
acl_user=acl_user_search;
acl_user= acl_user_search;
/* Store it as a cache */
*hint_user=acl_user;
*cur_priv_version=priv_version;
*cached_user= acl_user;
*cur_priv_version= priv_version;
break;
}
}
}
}
/* Now we have acl_user found and may start our checks */
if (acl_user)
{
/* Password should present for both or absend for both */
if (!acl_user->password && !*password ||
(acl_user->password && *password))
{
/* Quick check and accept for empty passwords*/
if (!acl_user->password && !*password)
password_correct=1;
else /* Normal password presents */
else if (!acl_user->password || !*password)
{
*cached_user= 0; // Impossible to connect
}
else
{
/* New version password is checked differently */
if (acl_user->pversion)
......@@ -580,7 +579,6 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
}
}
}
}
/* If user not found password_correct will also be zero */
if (!password_correct)
......@@ -1120,7 +1118,10 @@ bool change_password(THD *thd, const char *host, const char *user,
if (check_change_password(thd, host, user))
DBUG_RETURN(1);
/* password should always be 0,16 or 45 chars; simple hack to avoid cracking */
/*
password should always be 0,16 or 45 chars;
Simple hack to avoid cracking
*/
length=(uint) strlen(new_password);
if (length!=45)
......
......@@ -225,7 +225,7 @@ public:
return (void*) sql_calloc((uint) size);
}
static void operator delete(void *ptr,size_t size) {}
st_select_lex_node() {}
st_select_lex_node(): linkage(UNSPECIFIED_TYPE) {}
virtual ~st_select_lex_node() {}
inline st_select_lex_node* get_master() { return master; }
virtual void init_query();
......
......@@ -181,32 +181,57 @@ end:
/*
Check if user is ok
Updates:
thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access
SYNOPSIS
check_user()
thd Thread handle
command Command for connection (for log)
user Name of user trying to connect
passwd Scrambled password sent from client
db Database to connect to
check_count If set to 1, don't allow too many connection
simple_connect If 1 then client is of old type and we should connect
using the old method (no challange)
do_send_error Set to 1 if we should send error to user
prepared_scramble Buffer to store hash password of new connection
had_password Set to 1 if the user gave a password
cur_priv_version Check flag to know if someone flushed the privileges
since last code
hint_user Pointer used by acl_getroot() to remmeber user for
next call
RETURN
0 ok
thd->user, thd->master_access, thd->priv_user, thd->db and
thd->db_access are updated
1 Access denied; Error sent to client
-1 If do_send_error == 1: Failed connect, error sent to client
If do_send_error == 0: Prepare for stage of connect
*/
static int check_user(THD *thd,enum_server_command command, const char *user,
const char *passwd, const char *db, bool check_count,
bool simple_connect, bool do_send_error,
char *crypted_scramble, bool had_password,
char *prepared_scramble, bool had_password,
uint *cur_priv_version, ACL_USER** hint_user)
{
thd->db=0;
thd->db_length=0;
USER_RESOURCES ur;
DBUG_ENTER("check_user");
/* We shall avoid dupplicate user allocations here */
if (!thd->user && !(thd->user = my_strdup(user, MYF(0))))
{
send_error(thd,ER_OUT_OF_RESOURCES);
return 1;
DBUG_RETURN(1);
}
thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
passwd, thd->scramble, &thd->priv_user,
(protocol_version == 9 ||
!(thd->client_capabilities &
CLIENT_LONG_PASSWORD)),
&ur,crypted_scramble,
&ur,prepared_scramble,
cur_priv_version,hint_user);
DBUG_PRINT("info",
......@@ -222,8 +247,9 @@ static int check_user(THD *thd,enum_server_command command, const char *user,
*/
if (thd->master_access & NO_ACCESS)
{
if (do_send_error)
if (do_send_error || !had_password || !*hint_user)
{
DBUG_PRINT("info",("Access denied"));
/*
Old client should get nicer error message if password version is
not supported
......@@ -244,10 +270,10 @@ static int check_user(THD *thd,enum_server_command command, const char *user,
thd->host_or_ip,
had_password ? ER(ER_YES) : ER(ER_NO));
}
return(1); // Error already given
DBUG_RETURN(1); // Error already given
}
else
return(-1); // do not report error in special handshake
DBUG_PRINT("info",("Prepare for second part of handshake"));
DBUG_RETURN(-1); // no report error in special handshake
}
if (check_count)
......@@ -259,7 +285,7 @@ static int check_user(THD *thd,enum_server_command command, const char *user,
if (tmp)
{ // Too many connections
send_error(thd, ER_CON_COUNT_ERROR);
return(1);
DBUG_RETURN(1);
}
}
mysql_log.write(thd,command,
......@@ -273,21 +299,20 @@ static int check_user(THD *thd,enum_server_command command, const char *user,
/* Don't allow user to connect if he has done too many queries */
if ((ur.questions || ur.updates || ur.connections) &&
get_or_create_user_conn(thd,user,thd->host_or_ip,&ur))
return -1;
DBUG_RETURN(1);
if (thd->user_connect && thd->user_connect->user_resources.connections &&
check_for_max_user_connections(thd, thd->user_connect))
return -1;
DBUG_RETURN(1);
if (db && db[0])
{
bool error=test(mysql_change_db(thd,db));
int error= test(mysql_change_db(thd,db));
if (error && thd->user_connect)
decrease_user_connections(thd->user_connect);
return error;
DBUG_RETURN(error);
}
else
send_ok(thd); // Ready to handle questions
return 0; // ok
DBUG_RETURN(0); // ok
}
......@@ -492,24 +517,35 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
/*
Check connnetion and get priviliges
Returns 0 on ok, -1 < if error is given > 0 on error.
Check connnectionn and get priviliges
SYNOPSIS
check_connections
thd Thread handle
RETURN
0 ok
-1 Error, which is sent to user
> 0 Error code (not sent to user)
*/
#ifndef EMBEDDED_LIBRARY
static int
check_connections(THD *thd)
{
int res;
uint connect_errors=0;
uint cur_priv_version;
bool using_password;
NET *net= &thd->net;
char *end, *user, *passwd, *db;
char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble&hash */
ACL_USER* cached_user=NULL; /* Initialise to NULL for first stage */
uint cur_priv_version;
DBUG_PRINT("info",("New connection received on %s",
vio_description(net->vio)));
/* Remove warning from valgrind. TODO: Fix it in password.c */
bzero((char*) prepared_scramble, sizeof(prepared_scramble));
bzero((char*) &prepared_scramble[0], sizeof(prepared_scramble));
if (!thd->host) // If TCP/IP connection
{
char ip[30];
......@@ -648,11 +684,12 @@ check_connections(THD *thd)
user= end;
passwd= strend(user)+1;
db=0;
using_password= test(passwd[0]);
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
db=strend(passwd)+1;
/* We can get only old hash at this point */
if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
if (using_password && strlen(passwd) != SCRAMBLE_LENGTH)
return ER_HANDSHAKE_ERROR;
if (thd->client_capabilities & CLIENT_INTERACTIVE)
......@@ -665,24 +702,23 @@ check_connections(THD *thd)
/* Simple connect only for old clients. New clients always use secure auth */
bool simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
/* Store information if we used password. passwd will be dammaged */
bool using_password=test(passwd[0]);
/* Check user permissions. If password failure we'll get scramble back */
if (check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect,
if ((res=check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect,
simple_connect, prepared_scramble, using_password,
&cur_priv_version,
&cached_user)<0)
&cached_user)) < 0)
{
/* Store current used and database as they are erased with next packet */
char tmp_user[USERNAME_LENGTH+1];
char tmp_db[NAME_LEN+1];
tmp_user[0]= tmp_db[0]= 0;
/* If The client is old we just have to return error */
/* If the client is old we just have to return error */
if (simple_connect)
return -1;
DBUG_PRINT("info",("password challenge"));
tmp_user[0]= tmp_db[0]= 0;
if (user)
strmake(tmp_user,user,USERNAME_LENGTH);
if (db)
......@@ -714,10 +750,13 @@ check_connections(THD *thd)
&cached_user))
return -1;
}
else if (res)
return -1; // Error sent from check_user()
thd->password=using_password;
return 0;
}
pthread_handler_decl(handle_one_connection,arg)
{
THD *thd=(THD*) arg;
......@@ -1014,14 +1053,15 @@ bool do_command(THD *thd)
net->read_timeout=old_timeout; // restore it
DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
}
#endif /* EMBEDDED_LIBRARY */
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length)
{
int res;
NET *net= &thd->net;
bool error=0;
bool error= 0;
/*
Commands which will always take a long time should be marked with
this so that they will not get logged to the slow query log
......@@ -1098,6 +1138,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
uint cur_priv_version; /* Cached grant version */
ulong pkt_len=0; /* Length of reply packet */
bzero((char*) prepared_scramble, sizeof(prepared_scramble));
/* Small check for incomming packet */
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
......@@ -1124,11 +1165,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
Check user permissions. If password failure we'll get scramble back
Do not retry if we already have sent error (result>0)
*/
if (check_user(thd,COM_CHANGE_USER, user, passwd, db, 0, simple_connect,
simple_connect, prepared_scramble, using_password, &cur_priv_version,
&cached_user) < 0)
if ((res=check_user(thd,COM_CHANGE_USER, user, passwd, db, 0,
simple_connect, simple_connect, prepared_scramble,
using_password, &cur_priv_version, &cached_user)) < 0)
{
/* If The client is old we just have to have auth failure */
/* If the client is old we just have to have auth failure */
if (simple_connect)
goto restore_user; /* Error is already reported */
......@@ -1149,16 +1190,18 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
goto restore_user_err;
/* We have to get very specific packet size */
if (pkt_len!=SCRAMBLE41_LENGTH)
if (pkt_len != SCRAMBLE41_LENGTH)
goto restore_user;
/* Final attempt to check the user based on reply */
if (check_user(thd,COM_CHANGE_USER, tmp_user, (char*) net->read_pos,
tmp_db, 0, 0, 1, prepared_scramble, using_password,
&cur_priv_version,
&cached_user))
&cur_priv_version, &cached_user))
goto restore_user;
}
else if (res)
goto restore_user;
/* Finally we've authenticated new user */
if (max_connections && save_uc)
decrease_user_connections(save_uc);
......@@ -1168,10 +1211,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
/* Bad luck we shall restore old user */
restore_user_err:
restore_user_err:
send_error(thd, ER_UNKNOWN_COM_ERROR);
restore_user:
restore_user:
x_free(thd->user);
thd->master_access=save_master_access;
thd->db_access=save_db_access;
......
......@@ -639,9 +639,11 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
value=value*10L + (long) (*str - '0');
if (*str == ' ')
/* Move to last space */
if (str != end && *str == ' ')
{
while (++str != end && str[0] == ' ') ;
while (++str != end && str[0] == ' ')
{}
str--;
}
......
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