diff --git a/.bzrignore b/.bzrignore index 99e6c82316f7dbb215872dd1400e897604cd7f91..28264672c82ae9941b7d39ca17425a0f4a7debed 100644 --- a/.bzrignore +++ b/.bzrignore @@ -597,3 +597,4 @@ vio/test-sslclient vio/test-sslserver vio/viotest-ssl scripts/fill_help_tables.sql +scripts/fill_help_tables diff --git a/client/mysqltest.c b/client/mysqltest.c index f417018dbb74a101a5137a3d8720242838d47078..c8e839695652fbaa5154c293aac9349c47f1b364 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -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); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 29f23b4ecc56deabfea57d08829d5683c37de190..95b3250ae94194c87d37557903562d8e5dcae7da 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -215,31 +215,32 @@ 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,10 +259,11 @@ 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; if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0) @@ -276,6 +278,7 @@ my_bool my_connect(my_socket s, const struct sockaddr *name, #endif } + /* Create a named pipe connection */ @@ -348,15 +351,17 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host, } #endif + /* Create new shared memory connection, return handler of connection SYNOPSIS create_shared_memory() - mysql Pointer of mysql structure - net Pointer of net structure - connect_timeout Timeout of connection + mysql Pointer of mysql structure + 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 -*/ + /* + 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) + /* + Wait of answer from server + */ + 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 -*/ + /* + 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: + /* + 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 -*/ + 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 -*/ + /* + 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 *****************************************************************************/ @@ -1799,10 +1820,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)) @@ -1825,10 +1847,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 @@ -1850,6 +1872,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 @@ -1887,7 +1978,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; @@ -1933,7 +2023,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]) @@ -1943,30 +2033,29 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, if (!unix_socket) unix_socket=mysql->options.unix_socket; - mysql->reconnect=1; /* Reconnect as default */ + mysql->reconnect=1; /* Reconnect as default */ 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)) == INVALID_HANDLE_VALUE) { DBUG_PRINT("error", - ("host: '%s' socket: '%s' shared memory: %s have_tcpip: %d", - host ? host : "<null>", - unix_socket ? unix_socket : "<null>", - (int) mysql->options.shared_memory_base_name, - (int) have_tcpip)); - if (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY) - goto error; -/* -Try also with PIPE or TCP/IP -*/ + ("host: '%s' socket: '%s' shared memory: %s have_tcpip: %d", + host ? host : "<null>", + unix_socket ? unix_socket : "<null>", + (int) mysql->options.shared_memory_base_name, + (int) have_tcpip)); + if (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY) + goto error; + /* Try also with PIPE or TCP/IP */ } else { @@ -1977,70 +2066,76 @@ 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)) - { - host=LOCAL_HOST; - if (!unix_socket) - unix_socket=mysql_unix_port; - host_info=(char*) ER(CR_LOCALHOST_CONNECTION); - DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket)); - if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR) - { - net->last_errno=CR_SOCKET_CREATE_ERROR; - sprintf(net->last_error,ER(net->last_errno),socket_errno); - goto error; - } - net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE); - bzero((char*) &UNIXaddr,sizeof(UNIXaddr)); - UNIXaddr.sun_family = AF_UNIX; - strmov(UNIXaddr.sun_path, unix_socket); - if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr), - mysql->options.connect_timeout)) + if ((!mysql->options.protocol || + mysql->options.protocol == MYSQL_PROTOCOL_SOCKET)&& + (!host || !strcmp(host,LOCAL_HOST)) && + (unix_socket || mysql_unix_port)) { - 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; + host=LOCAL_HOST; + if (!unix_socket) + unix_socket=mysql_unix_port; + host_info=(char*) ER(CR_LOCALHOST_CONNECTION); + DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket)); + if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR) + { + net->last_errno=CR_SOCKET_CREATE_ERROR; + sprintf(net->last_error,ER(net->last_errno),socket_errno); + goto error; + } + net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE); + bzero((char*) &UNIXaddr,sizeof(UNIXaddr)); + UNIXaddr.sun_family = AF_UNIX; + strmov(UNIXaddr.sun_path, unix_socket); + 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)); + net->last_errno=CR_CONNECTION_ERROR; + sprintf(net->last_error,ER(net->last_errno),unix_socket,socket_errno); + goto error; + } + else + mysql->options.protocol=MYSQL_PROTOCOL_SOCKET; } else - mysql->options.protocol=MYSQL_PROTOCOL_SOCKET; - } - else #elif defined(__WIN__) - 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)) - { - sock=0; - if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout, - (char**) &host, (char**) &unix_socket)) == - INVALID_HANDLE_VALUE) { - DBUG_PRINT("error", - ("host: '%s' socket: '%s' have_tcpip: %d", - host ? host : "<null>", - unix_socket ? unix_socket : "<null>", - (int) have_tcpip)); - if (mysql->options.protocol == MYSQL_PROTOCOL_PIPE || - (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) || - (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE))) - goto error; - /* - Try also with TCP/IP - */ - } - else - { - net->vio=vio_new_win32pipe(hPipe); - sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host, - unix_socket); + 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)) + { + sock=0; + if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout, + (char**) &host, (char**) &unix_socket)) == + INVALID_HANDLE_VALUE) + { + DBUG_PRINT("error", + ("host: '%s' socket: '%s' have_tcpip: %d", + host ? host : "<null>", + unix_socket ? unix_socket : "<null>", + (int) have_tcpip)); + if (mysql->options.protocol == MYSQL_PROTOCOL_PIPE || + (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) || + (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE))) + goto error; + /* Try also with TCP/IP */ + } + else + { + net->vio=vio_new_win32pipe(hPipe); + sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host, + 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) @@ -2061,7 +2156,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) @@ -2087,22 +2182,22 @@ Try also with PIPE or TCP/IP } sock_addr.sin_port = (ushort) htons((ushort) port); if (my_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr), - mysql->options.connect_timeout)) + 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) - { - 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; - }; + 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)) { @@ -2170,7 +2265,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; @@ -2235,7 +2329,7 @@ Try also with PIPE or TCP/IP client_flag|=CLIENT_CONNECT_WITH_DB; /* Remove options that server doesn't support */ client_flag= ((client_flag & - ~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41)) | + ~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41)) | (client_flag & mysql->server_capabilities)); #ifndef HAVE_COMPRESS @@ -2311,7 +2405,7 @@ Try also with PIPE or TCP/IP /* We always start with old type handshake the only difference is message sent If server handles secure connection type we'll not send the real scramble - */ + */ if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) { if (passwd[0]) @@ -2322,17 +2416,17 @@ Try also with PIPE or TCP/IP end+=SCRAMBLE_LENGTH; *end=0; } - else /* For empty password*/ + else /* For empty password*/ { end=strend(end)+1; - *end=0; /* Store zero length scramble */ + *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); + Real scramble is only sent to old servers. This can be blocked + by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1); */ end=scramble(strend(end)+1, mysql->scramble_buff, passwd, (my_bool) (mysql->protocol_version == 9)); @@ -2352,59 +2446,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) @@ -2524,10 +2568,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) @@ -2556,83 +2596,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); + 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); - } @@ -5105,6 +5098,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); @@ -5113,7 +5107,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; } diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index a1fbaaae631cb193856c1724e3874b9c83e3c9b3..c989ee0c89ffdba8f43c749140ce41bf9b44b16c 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -373,13 +373,22 @@ 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; diff --git a/mysql-test/r/rpl_user_variables.result b/mysql-test/r/rpl_user_variables.result index 618efb3840d430b1b41b9a4781bc1d7ec7711410..51a82b530522f3fe6ee433c4d86835361da1858e 100644 --- a/mysql-test/r/rpl_user_variables.result +++ b/mysql-test/r/rpl_user_variables.result @@ -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; diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index ba8e01d631931269a448e88afd7775035ae1ea16..3ad8c8baec37ae9d54eacb0deb3ac88e4ea1d0b0 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -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 diff --git a/mysql-test/t/rpl_user_variables.test b/mysql-test/t/rpl_user_variables.test index 7de52367fba84cf8231d7eb58cb53eb74f4ac83b..561af7256d27ddb2a3d7c41ee3458aea0dbb19b8 100644 --- a/mysql-test/t/rpl_user_variables.test +++ b/mysql-test/t/rpl_user_variables.test @@ -1,14 +1,8 @@ +# +# 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; diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test index 6a55c61f8a1d1c6ed61f5f87f002d832e87838e0..1de08ff4e4dbe8ea04164c6ac8cd508b81ad55c6 100644 --- a/mysql-test/t/type_blob.test +++ b/mysql-test/t/type_blob.test @@ -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; diff --git a/sql/item.cc b/sql/item.cc index ee7af1ae0fdf9e23fcb54f1e60795d8fc77054d0..50f872351963633945e3dcd84cfcb7be987d1fe0 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -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) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index b189f34912c5086ab5c2eb7cae76e52bf35600db..8804bb56f6b57b9bf769a2802938474c8ba1ce29 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -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) diff --git a/sql/item_func.cc b/sql/item_func.cc index 2c8b9e97fb3098976652819df7ddc5684af66554..45d666fb47b467f8a0e6063946a3dbf00b52cb9c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -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)); diff --git a/sql/log_event.cc b/sql/log_event.cc index 0631e21fbd142c841569da5f25a30b61ec844529..6bd187ab8afd0a6005859bf1f82aed6d8fe27eb0 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -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() +/**************************************************************************** + Rand_log_event methods +****************************************************************************/ - ****************************************************************************/ #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 methods +***************************************************************************/ - User_var_log_event::pack_info() - - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void User_var_log_event::pack_info(Protocol* protocol) { @@ -2019,8 +1985,8 @@ 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, - (buf + val_offset, "%.14g", real_val)); + event_len+= my_sprintf(buf + val_offset, + (buf + val_offset, "%.14g", real_val)); break; case INT_RESULT: buf= my_malloc(val_offset + 22, MYF(MY_WME)); @@ -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() - - ****************************************************************************/ +/**************************************************************************** + Slave_log_event methods +****************************************************************************/ #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) { diff --git a/sql/log_event.h b/sql/log_event.h index 567bf279ff10676a9f412c5a1a2b38e745647335..b9b1355a30456a75472de9b3d93249bda0ab0806 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -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, diff --git a/sql/mini_client.cc b/sql/mini_client.cc index 2ee4b551d7138c37a58d32a6a45f3acf761a5cba..db3a51712f2d8c111864a4ef495acc5d817adeed 100644 --- a/sql/mini_client.cc +++ b/sql/mini_client.cc @@ -830,13 +830,15 @@ 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); + Real scramble is only sent to old servers. This can be blocked + by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1); */ 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)) { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index dd5bee2eed5e29d4968b2c4f80ea8b880e6cce6f..570bddfe773ad61d9f7459b71600e6d96109f96d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -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); diff --git a/sql/protocol.cc b/sql/protocol.cc index c338feea9bc07877de95ac1d2d3705bbb3fd8c78..ebee87806db2a6cee9fcf62c2fd3a6be4b8380c4 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -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); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 40dddaad08e89f978d9e5edc22570f60d7fcf51b..41b825e3322a8ed0c47f67037edc483e82a35b9a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -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,60 +530,59 @@ 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)) + if (!acl_user->password && !*password) + password_correct=1; + else if (!acl_user->password || !*password) { - /* Quick check and accept for empty passwords*/ - if (!acl_user->password && !*password) - password_correct=1; - else /* Normal password presents */ + *cached_user= 0; // Impossible to connect + } + else + { + /* New version password is checked differently */ + if (acl_user->pversion) { - /* New version password is checked differently */ - if (acl_user->pversion) - { - if (stage) /* We check password only on the second stage */ - { - if (!validate_password(password,message,acl_user->salt)) - password_correct=1; - } - else /* First stage - just prepare scramble */ - prepare_scramble(thd,acl_user,prepared_scramble); - } - /* Old way to check password */ - else - { - /* Checking the scramble at any stage. First - old clients */ - if (!check_scramble(password,message,acl_user->salt, - (my_bool) old_ver)) - password_correct=1; - else if (!stage) /* Here if password incorrect */ - { - /* At the first stage - prepare scramble */ - prepare_scramble(thd,acl_user,prepared_scramble); - } - } + if (stage) /* We check password only on the second stage */ + { + if (!validate_password(password,message,acl_user->salt)) + password_correct=1; + } + else /* First stage - just prepare scramble */ + prepare_scramble(thd,acl_user,prepared_scramble); + } + /* Old way to check password */ + else + { + /* Checking the scramble at any stage. First - old clients */ + if (!check_scramble(password,message,acl_user->salt, + (my_bool) old_ver)) + password_correct=1; + else if (!stage) /* Here if password incorrect */ + { + /* At the first stage - prepare scramble */ + prepare_scramble(thd,acl_user,prepared_scramble); + } } } } /* If user not found password_correct will also be zero */ if (!password_correct) - goto unlock_and_exit; + goto unlock_and_exit; /* OK. User found and password checked continue validation */ @@ -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) diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index a424d8779199f8301791d06f4ba2e34314759ba6..192ef24717777d6cae6c637daf547e10e0c03cfd 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -89,6 +89,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, if ((*param->item)->type() != Item::INT_ITEM || (*param->item)->val() < 0) { + delete pc; my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name); DBUG_RETURN(0); } @@ -103,6 +104,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, if ((*param->item)->type() != Item::INT_ITEM || (*param->item)->val() < 0) { + delete pc; my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name); DBUG_RETURN(0); } @@ -111,6 +113,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, else if ((*param->item)->type() != Item::INT_ITEM || (*param->item)->val() < 0) { + delete pc; my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name); DBUG_RETURN(0); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index ae98a554150f6179b89680f3633ad2d4638a5687..aff3485dbe46496fbffb2b2a1d4cc4b585eb95db 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -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(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ba5862a7fde764fb11153c26415d62071ddb40a6..d69f95e724821005f99693068f4db450e7187de3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -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 + send_ok(thd); // Ready to handle questions + 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, - simple_connect, prepared_scramble, using_password, - &cur_priv_version, - &cached_user)<0) + 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) { /* 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,13 +1165,13 @@ 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 */ + goto restore_user; /* Error is already reported */ /* Store current used and database as they are erased with next packet */ tmp_user[0]= tmp_db[0]= 0; @@ -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)) + tmp_db, 0, 0, 1, prepared_scramble, using_password, + &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; diff --git a/sql/time.cc b/sql/time.cc index 6b2f8b710da89cc270359c53cccb488b6ffedc4b..94f9cb2e5e83c72182d2c7585127dcdf02e8fc5c 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -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--; }