diff options
author | click <none@none> | 2010-08-07 19:01:57 +0200 |
---|---|---|
committer | click <none@none> | 2010-08-07 19:01:57 +0200 |
commit | ce435f6d4f84462c0707bbc608d767648d5e99c3 (patch) | |
tree | dabac44fd559c925acf2171adb0ae3038f05ad7b /externals/mysql/libmysql/client.c | |
parent | 3cc24e0971f96b9ffa4032a154750e4224ea499d (diff) |
BuildSystem/VS: Remove now defunct an unmaintained buildfiles - use CMake for generating solutionfiles
--HG--
branch : trunk
Diffstat (limited to 'externals/mysql/libmysql/client.c')
-rw-r--r-- | externals/mysql/libmysql/client.c | 3268 |
1 files changed, 0 insertions, 3268 deletions
diff --git a/externals/mysql/libmysql/client.c b/externals/mysql/libmysql/client.c deleted file mode 100644 index bf4cf36339b..00000000000 --- a/externals/mysql/libmysql/client.c +++ /dev/null @@ -1,3268 +0,0 @@ -/* Copyright (C) 2000-2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* - This file is included by both libmysql.c (the MySQL client C API) - and the mysqld server to connect to another MYSQL server. - - The differences for the two cases are: - - - Things that only works for the client: - - Trying to automaticly determinate user name if not supplied to - mysql_real_connect() - - Support for reading local file with LOAD DATA LOCAL - - SHARED memory handling - - Protection against sigpipe - - Prepared statements - - - Things that only works for the server - - Alarm handling on connect - - In all other cases, the code should be idential for the client and - server. -*/ - -#include <my_global.h> - -#include "mysql.h" - -#ifndef __WIN__ -#include <netdb.h> -#endif - -/* Remove client convenience wrappers */ -#undef max_allowed_packet -#undef net_buffer_length - -#ifdef EMBEDDED_LIBRARY - -#undef MYSQL_SERVER - -#ifndef MYSQL_CLIENT -#define MYSQL_CLIENT -#endif - -#define CLI_MYSQL_REAL_CONNECT STDCALL cli_mysql_real_connect - -#undef net_flush -my_bool net_flush(NET *net); - -#else /*EMBEDDED_LIBRARY*/ -#define CLI_MYSQL_REAL_CONNECT STDCALL mysql_real_connect -#endif /*EMBEDDED_LIBRARY*/ -#include <my_sys.h> -#include <mysys_err.h> -#include <m_string.h> -#include <m_ctype.h> -#include "mysql_version.h" -#include "mysqld_error.h" -#include "errmsg.h" -#include <violite.h> -#if defined(THREAD) && !defined(__WIN__) -#include <my_pthread.h> /* because of signal() */ -#endif /* defined(THREAD) && !defined(__WIN__) */ - -#include <sys/stat.h> -#include <signal.h> -#include <time.h> -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#if !defined(MSDOS) && !defined(__WIN__) -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> -#ifdef HAVE_SELECT_H -# include <select.h> -#endif -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif -#endif /*!defined(MSDOS) && !defined(__WIN__) */ -#ifdef HAVE_SYS_UN_H -# include <sys/un.h> -#endif - -#if defined(MSDOS) || defined(__WIN__) -#define perror(A) -#else -#include <errno.h> -#define SOCKET_ERROR -1 -#endif - -#ifdef __WIN__ -#define CONNECT_TIMEOUT 20 -#else -#define CONNECT_TIMEOUT 0 -#endif - -#include "client_settings.h" -#include <sql_common.h> - -uint mysql_port=0; -char *mysql_unix_port= 0; -const char *unknown_sqlstate= "HY000"; -const char *not_error_sqlstate= "00000"; -const char *cant_connect_sqlstate= "08001"; -#ifdef HAVE_SMEM -char *shared_memory_base_name= 0; -const char *def_shared_memory_base_name= default_shared_memory_base_name; -#endif - -static void mysql_close_free_options(MYSQL *mysql); -static void mysql_close_free(MYSQL *mysql); - -#if !(defined(__WIN__) || defined(__NETWARE__)) -static int wait_for_data(my_socket fd, uint timeout); -#endif - -CHARSET_INFO *default_client_charset_info = &my_charset_latin1; - -/* Server error code and message */ -unsigned int mysql_server_last_errno; -char mysql_server_last_error[MYSQL_ERRMSG_SIZE]; - -/**************************************************************************** - A modified version of connect(). my_connect() allows you to specify - a timeout value, in seconds, that we should wait until we - derermine we can't connect to a particular host. If timeout is 0, - my_connect() will behave exactly like connect(). - - Base version coded by Steve Bernacki, Jr. <steve@navinet.net> -*****************************************************************************/ - -int my_connect(my_socket fd, const struct sockaddr *name, uint namelen, - uint timeout) -{ -#if defined(__WIN__) || defined(__NETWARE__) - return connect(fd, (struct sockaddr*) name, namelen); -#else - int flags, res, s_err; - - /* - If they passed us a timeout of zero, we should behave - exactly like the normal connect() call does. - */ - - if (timeout == 0) - return connect(fd, (struct sockaddr*) name, namelen); - - flags = fcntl(fd, F_GETFL, 0); /* Set socket to not block */ -#ifdef O_NONBLOCK - fcntl(fd, F_SETFL, flags | O_NONBLOCK); /* and save the flags.. */ -#endif - - res= connect(fd, (struct sockaddr*) name, namelen); - s_err= errno; /* Save the error... */ - fcntl(fd, F_SETFL, flags); - if ((res != 0) && (s_err != EINPROGRESS)) - { - errno= s_err; /* Restore it */ - return(-1); - } - if (res == 0) /* Connected quickly! */ - return(0); - return wait_for_data(fd, timeout); -#endif -} - - -/* - Wait up to timeout seconds for a connection to be established. - - We prefer to do this with poll() as there is no limitations with this. - If not, we will use select() -*/ - -#if !(defined(__WIN__) || defined(__NETWARE__)) - -static int wait_for_data(my_socket fd, uint timeout) -{ -#ifdef HAVE_POLL - struct pollfd ufds; - int res; - - ufds.fd= fd; - ufds.events= POLLIN | POLLPRI; - if (!(res= poll(&ufds, 1, (int) timeout*1000))) - { - errno= EINTR; - return -1; - } - if (res < 0 || !(ufds.revents & (POLLIN | POLLPRI))) - return -1; - return 0; -#else - socklen_t s_err_size = sizeof(uint); - fd_set sfds; - struct timeval tv; - time_t start_time, now_time; - int res, s_err; - - if (fd >= FD_SETSIZE) /* Check if wrong error */ - return 0; /* Can't use timeout */ - - /* - 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. - */ - - FD_ZERO(&sfds); - FD_SET(fd, &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 - */ - start_time= my_time(0); - for (;;) - { - tv.tv_sec = (long) timeout; - tv.tv_usec = 0; -#if defined(HPUX10) && defined(THREAD) - if ((res = select(fd+1, NULL, (int*) &sfds, NULL, &tv)) > 0) - break; -#else - if ((res = select(fd+1, NULL, &sfds, NULL, &tv)) > 0) - break; -#endif - if (res == 0) /* timeout */ - return -1; - now_time= my_time(0); - timeout-= (uint) (now_time - start_time); - if (errno != EINTR || (int) timeout <= 0) - 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! - */ - - s_err=0; - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0) - return(-1); - - if (s_err) - { /* getsockopt could succeed */ - errno = s_err; - return(-1); /* but return an error... */ - } - return (0); /* ok */ -#endif /* HAVE_POLL */ -} -#endif /* defined(__WIN__) || defined(__NETWARE__) */ - -/** - Set the internal error message to mysql handler - - @param mysql connection handle (client side) - @param errcode CR_ error code, passed to ER macro to get - error text - @parma sqlstate SQL standard sqlstate -*/ - -void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate) -{ - NET *net; - DBUG_ENTER("set_mysql_error"); - DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER(errcode))); - DBUG_ASSERT(mysql != 0); - - if (mysql) - { - net= &mysql->net; - net->last_errno= errcode; - strmov(net->last_error, ER(errcode)); - strmov(net->sqlstate, sqlstate); - } - else - { - mysql_server_last_errno= errcode; - strmov(mysql_server_last_error, ER(errcode)); - } - DBUG_VOID_RETURN; -} - -/** - Clear possible error state of struct NET - - @param net clear the state of the argument -*/ - -void net_clear_error(NET *net) -{ - net->last_errno= 0; - net->last_error[0]= '\0'; - strmov(net->sqlstate, not_error_sqlstate); -} - -/** - Set an error message on the client. - - @param mysql connection handle - @param errcode CR_* errcode, for client errors - @param sqlstate SQL standard sql state, unknown_sqlstate for the - majority of client errors. - @param format error message template, in sprintf format - @param ... variable number of arguments -*/ - -static void set_mysql_extended_error(MYSQL *mysql, int errcode, - const char *sqlstate, - const char *format, ...) -{ - NET *net; - va_list args; - DBUG_ENTER("set_mysql_extended_error"); - DBUG_PRINT("enter", ("error :%d '%s'", errcode, format)); - DBUG_ASSERT(mysql != 0); - - net= &mysql->net; - net->last_errno= errcode; - va_start(args, format); - my_vsnprintf(net->last_error, sizeof(net->last_error)-1, - format, args); - va_end(args); - strmov(net->sqlstate, sqlstate); - - DBUG_VOID_RETURN; -} - - - -/* - Create a named pipe connection -*/ - -#ifdef __WIN__ - -HANDLE create_named_pipe(MYSQL *mysql, uint connect_timeout, char **arg_host, - char **arg_unix_socket) -{ - HANDLE hPipe=INVALID_HANDLE_VALUE; - char pipe_name[1024]; - DWORD dwMode; - int i; - my_bool testing_named_pipes=0; - char *host= *arg_host, *unix_socket= *arg_unix_socket; - - if ( ! unix_socket || (unix_socket)[0] == 0x00) - unix_socket = mysql_unix_port; - if (!host || !strcmp(host,LOCAL_HOST)) - host=LOCAL_HOST_NAMEDPIPE; - - - pipe_name[sizeof(pipe_name)-1]= 0; /* Safety if too long string */ - strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\", host, "\\pipe\\", - unix_socket, NullS); - DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s", host, unix_socket)); - - for (i=0 ; i < 100 ; i++) /* Don't retry forever */ - { - if ((hPipe = CreateFile(pipe_name, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - 0, - NULL )) != INVALID_HANDLE_VALUE) - break; - if (GetLastError() != ERROR_PIPE_BUSY) - { - set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR, - unknown_sqlstate, ER(CR_NAMEDPIPEOPEN_ERROR), - host, unix_socket, (ulong) GetLastError()); - return INVALID_HANDLE_VALUE; - } - /* wait for for an other instance */ - if (! WaitNamedPipe(pipe_name, connect_timeout*1000) ) - { - set_mysql_extended_error(mysql, CR_NAMEDPIPEWAIT_ERROR, unknown_sqlstate, - ER(CR_NAMEDPIPEWAIT_ERROR), - host, unix_socket, (ulong) GetLastError()); - return INVALID_HANDLE_VALUE; - } - } - if (hPipe == INVALID_HANDLE_VALUE) - { - set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR, unknown_sqlstate, - ER(CR_NAMEDPIPEOPEN_ERROR), host, unix_socket, - (ulong) GetLastError()); - return INVALID_HANDLE_VALUE; - } - dwMode = PIPE_READMODE_BYTE | PIPE_WAIT; - if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) ) - { - CloseHandle( hPipe ); - set_mysql_extended_error(mysql, CR_NAMEDPIPESETSTATE_ERROR, - unknown_sqlstate, ER(CR_NAMEDPIPESETSTATE_ERROR), - host, unix_socket, (ulong) GetLastError()); - return INVALID_HANDLE_VALUE; - } - *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */ - return (hPipe); -} -#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 -*/ - -#ifdef HAVE_SMEM -HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout) -{ - ulong smem_buffer_length = shared_memory_buffer_length + 4; - /* - event_connect_request is event object for start connection actions - event_connect_answer is event object for confirm, that server put data - handle_connect_file_map is file-mapping object, use for create shared - memory - handle_connect_map is pointer on shared memory - handle_map is pointer on shared memory for client - event_server_wrote, - event_server_read, - event_client_wrote, - event_client_read are events for transfer data between server and client - handle_file_map is file-mapping object, use for create shared memory - */ - HANDLE event_connect_request = NULL; - HANDLE event_connect_answer = NULL; - HANDLE handle_connect_file_map = NULL; - char *handle_connect_map = NULL; - - char *handle_map = NULL; - HANDLE event_server_wrote = NULL; - HANDLE event_server_read = NULL; - HANDLE event_client_wrote = NULL; - HANDLE event_client_read = NULL; - HANDLE event_conn_closed = NULL; - HANDLE handle_file_map = NULL; - ulong connect_number; - char connect_number_char[22], *p; - char *tmp= NULL; - char *suffix_pos; - DWORD error_allow = 0; - DWORD error_code = 0; - DWORD event_access_rights= SYNCHRONIZE | EVENT_MODIFY_STATE; - char *shared_memory_base_name = mysql->options.shared_memory_base_name; - - /* - get enough space base-name + '_' + longest suffix we might ever send - */ - if (!(tmp= (char *)my_malloc(strlen(shared_memory_base_name) + 32L, MYF(MY_FAE)))) - goto err; - - /* - The name of event and file-mapping events create agree next rule: - shared_memory_base_name+unique_part - Where: - shared_memory_base_name is unique value for each server - unique_part is uniquel value for each object (events and file-mapping) - */ - suffix_pos = strxmov(tmp, "Global\\", shared_memory_base_name, "_", NullS); - strmov(suffix_pos, "CONNECT_REQUEST"); - if (!(event_connect_request= OpenEvent(event_access_rights, FALSE, tmp))) - { - error_allow = CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR; - goto err; - } - strmov(suffix_pos, "CONNECT_ANSWER"); - if (!(event_connect_answer= OpenEvent(event_access_rights,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))) - { - 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)))) - { - 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) - { - error_allow = CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR; - goto err; - } - - /* Get number of connection */ - connect_number = uint4korr(handle_connect_map);/*WAX2*/ - p= int10_to_str(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, "Global\\", shared_memory_base_name, "_", connect_number_char, - "_", NullS); - strmov(suffix_pos, "DATA"); - if ((handle_file_map = OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)) == NULL) - { - error_allow = CR_SHARED_MEMORY_FILE_MAP_ERROR; - goto err2; - } - if ((handle_map = MapViewOfFile(handle_file_map,FILE_MAP_WRITE,0,0, - smem_buffer_length)) == NULL) - { - error_allow = CR_SHARED_MEMORY_MAP_ERROR; - goto err2; - } - - strmov(suffix_pos, "SERVER_WROTE"); - if ((event_server_wrote = OpenEvent(event_access_rights,FALSE,tmp)) == NULL) - { - error_allow = CR_SHARED_MEMORY_EVENT_ERROR; - goto err2; - } - - strmov(suffix_pos, "SERVER_READ"); - if ((event_server_read = OpenEvent(event_access_rights,FALSE,tmp)) == NULL) - { - error_allow = CR_SHARED_MEMORY_EVENT_ERROR; - goto err2; - } - - strmov(suffix_pos, "CLIENT_WROTE"); - if ((event_client_wrote = OpenEvent(event_access_rights,FALSE,tmp)) == NULL) - { - error_allow = CR_SHARED_MEMORY_EVENT_ERROR; - goto err2; - } - - strmov(suffix_pos, "CLIENT_READ"); - if ((event_client_read = OpenEvent(event_access_rights,FALSE,tmp)) == NULL) - { - error_allow = CR_SHARED_MEMORY_EVENT_ERROR; - goto err2; - } - - strmov(suffix_pos, "CONNECTION_CLOSED"); - if ((event_conn_closed = OpenEvent(event_access_rights,FALSE,tmp)) == NULL) - { - 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,event_conn_closed); - } - 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 (event_conn_closed) - CloseHandle(event_conn_closed); - if (handle_map) - UnmapViewOfFile(handle_map); - if (handle_file_map) - CloseHandle(handle_file_map); - } -err: - if (tmp) - my_free(tmp, MYF(0)); - 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) - { - if (error_allow == CR_SHARED_MEMORY_EVENT_ERROR) - set_mysql_extended_error(mysql, error_allow, unknown_sqlstate, - ER(error_allow), suffix_pos, error_code); - else - set_mysql_extended_error(mysql, error_allow, unknown_sqlstate, - ER(error_allow), error_code); - return(INVALID_HANDLE_VALUE); - } - return(handle_map); -} -#endif - -/** - Read a packet from server. Give error message if socket was down - or packet is an error message - - @retval packet_error An error occurred during reading. - Error message is set. - @retval -*/ - -ulong -cli_safe_read(MYSQL *mysql) -{ - NET *net= &mysql->net; - ulong len=0; - init_sigpipe_variables - - /* Don't give sigpipe errors if the client doesn't want them */ - set_sigpipe(mysql); - if (net->vio != 0) - len=my_net_read(net); - reset_sigpipe(mysql); - - if (len == packet_error || len == 0) - { - DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %lu", - vio_description(net->vio),len)); -#ifdef MYSQL_SERVER - if (net->vio && vio_was_interrupted(net->vio)) - return (packet_error); -#endif /*MYSQL_SERVER*/ - end_server(mysql); - set_mysql_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ? - CR_NET_PACKET_TOO_LARGE: CR_SERVER_LOST, unknown_sqlstate); - return (packet_error); - } - if (net->read_pos[0] == 255) - { - if (len > 3) - { - char *pos=(char*) net->read_pos+1; - net->last_errno=uint2korr(pos); - pos+=2; - len-=2; - if (protocol_41(mysql) && pos[0] == '#') - { - strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH); - pos+= SQLSTATE_LENGTH+1; - } - else - { - /* - The SQL state hasn't been received -- it should be reset to HY000 - (unknown error sql state). - */ - - strmov(net->sqlstate, unknown_sqlstate); - } - - (void) strmake(net->last_error,(char*) pos, - min((uint) len,(uint) sizeof(net->last_error)-1)); - } - else - set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate); - /* - Cover a protocol design error: error packet does not - contain the server status. Therefore, the client has no way - to find out whether there are more result sets of - a multiple-result-set statement pending. Luckily, in 5.0 an - error always aborts execution of a statement, wherever it is - a multi-statement or a stored procedure, so it should be - safe to unconditionally turn off the flag here. - */ - mysql->server_status&= ~SERVER_MORE_RESULTS_EXISTS; - - DBUG_PRINT("error",("Got error: %d/%s (%s)", - net->last_errno, - net->sqlstate, - net->last_error)); - return(packet_error); - } - return len; -} - -void free_rows(MYSQL_DATA *cur) -{ - if (cur) - { - free_root(&cur->alloc,MYF(0)); - my_free((uchar*) cur,MYF(0)); - } -} - -my_bool -cli_advanced_command(MYSQL *mysql, enum enum_server_command command, - const uchar *header, ulong header_length, - const uchar *arg, ulong arg_length, my_bool skip_check, - MYSQL_STMT *stmt) -{ - NET *net= &mysql->net; - my_bool result= 1; - init_sigpipe_variables - my_bool stmt_skip= stmt ? stmt->state != MYSQL_STMT_INIT_DONE : FALSE; - DBUG_ENTER("cli_advanced_command"); - - /* Don't give sigpipe errors if the client doesn't want them */ - set_sigpipe(mysql); - - if (mysql->net.vio == 0) - { /* Do reconnect if possible */ - if (mysql_reconnect(mysql) || stmt_skip) - DBUG_RETURN(1); - } - if (mysql->status != MYSQL_STATUS_READY || - mysql->server_status & SERVER_MORE_RESULTS_EXISTS) - { - DBUG_PRINT("error",("state: %d", mysql->status)); - set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); - DBUG_RETURN(1); - } - - net_clear_error(net); - mysql->info=0; - mysql->affected_rows= ~(my_ulonglong) 0; - /* - We don't want to clear the protocol buffer on COM_QUIT, because if - the previous command was a shutdown command, we may have the - response for the COM_QUIT already in the communication buffer - */ - net_clear(&mysql->net, (command != COM_QUIT)); - - if (net_write_command(net,(uchar) command, header, header_length, - arg, arg_length)) - { - DBUG_PRINT("error",("Can't send command to server. Error: %d", - socket_errno)); - if (net->last_errno == ER_NET_PACKET_TOO_LARGE) - { - set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate); - goto end; - } - end_server(mysql); - if (mysql_reconnect(mysql) || stmt_skip) - goto end; - if (net_write_command(net,(uchar) command, header, header_length, - arg, arg_length)) - { - set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate); - goto end; - } - } - result=0; - if (!skip_check) - result= ((mysql->packet_length=cli_safe_read(mysql)) == packet_error ? - 1 : 0); -end: - reset_sigpipe(mysql); - DBUG_PRINT("exit",("result: %d", result)); - DBUG_RETURN(result); -} - -void free_old_query(MYSQL *mysql) -{ - DBUG_ENTER("free_old_query"); - if (mysql->fields) - free_root(&mysql->field_alloc,MYF(0)); - init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */ - mysql->fields= 0; - mysql->field_count= 0; /* For API */ - mysql->warning_count= 0; - mysql->info= 0; - DBUG_VOID_RETURN; -} - - -/** - Finish reading of a partial result set from the server. - Get the EOF packet, and update mysql->status - and mysql->warning_count. - - @return TRUE if a communication or protocol error, an error - is set in this case, FALSE otherwise. -*/ - -my_bool flush_one_result(MYSQL *mysql) -{ - ulong packet_length; - - DBUG_ASSERT(mysql->status != MYSQL_STATUS_READY); - - do - { - packet_length= cli_safe_read(mysql); - /* - There is an error reading from the connection, - or (sic!) there were no error and no - data in the stream, i.e. no more data from the server. - Since we know our position in the stream (somewhere in - the middle of a result set), this latter case is an error too - -- each result set must end with a EOF packet. - cli_safe_read() has set an error for us, just return. - */ - if (packet_length == packet_error) - return TRUE; - } - while (packet_length > 8 || mysql->net.read_pos[0] != 254); - - /* Analyze EOF packet of the result set. */ - - if (protocol_41(mysql)) - { - char *pos= (char*) mysql->net.read_pos + 1; - mysql->warning_count=uint2korr(pos); - pos+=2; - mysql->server_status=uint2korr(pos); - pos+=2; - } - return FALSE; -} - - -/** - Read a packet from network. If it's an OK packet, flush it. - - @return TRUE if error, FALSE otherwise. In case of - success, is_ok_packet is set to TRUE or FALSE, - based on what we got from network. -*/ - -my_bool opt_flush_ok_packet(MYSQL *mysql, my_bool *is_ok_packet) -{ - ulong packet_length= cli_safe_read(mysql); - - if (packet_length == packet_error) - return TRUE; - - /* cli_safe_read always reads a non-empty packet. */ - DBUG_ASSERT(packet_length); - - *is_ok_packet= mysql->net.read_pos[0] == 0; - if (*is_ok_packet) - { - uchar *pos= mysql->net.read_pos + 1; - - net_field_length_ll(&pos); /* affected rows */ - net_field_length_ll(&pos); /* insert id */ - - mysql->server_status=uint2korr(pos); - pos+=2; - - if (protocol_41(mysql)) - { - mysql->warning_count=uint2korr(pos); - pos+=2; - } - } - return FALSE; -} - - -/* - Flush result set sent from server -*/ - -static void cli_flush_use_result(MYSQL *mysql, my_bool flush_all_results) -{ - /* Clear the current execution status */ - DBUG_ENTER("cli_flush_use_result"); - DBUG_PRINT("warning",("Not all packets read, clearing them")); - - if (flush_one_result(mysql)) - DBUG_VOID_RETURN; /* An error occurred */ - - if (! flush_all_results) - DBUG_VOID_RETURN; - - while (mysql->server_status & SERVER_MORE_RESULTS_EXISTS) - { - my_bool is_ok_packet; - if (opt_flush_ok_packet(mysql, &is_ok_packet)) - DBUG_VOID_RETURN; /* An error occurred. */ - if (is_ok_packet) - { - /* - Indeed what we got from network was an OK packet, and we - know that OK is the last one in a multi-result-set, so - just return. - */ - DBUG_VOID_RETURN; - } - /* - It's a result set, not an OK packet. A result set contains - of two result set subsequences: field metadata, terminated - with EOF packet, and result set data, again terminated with - EOF packet. Read and flush them. - */ - if (flush_one_result(mysql) || flush_one_result(mysql)) - DBUG_VOID_RETURN; /* An error occurred. */ - } - - DBUG_VOID_RETURN; -} - - -#ifdef __WIN__ -static my_bool is_NT(void) -{ - char *os=getenv("OS"); - return (os && !strcmp(os, "Windows_NT")) ? 1 : 0; -} -#endif - - -#ifdef CHECK_LICENSE -/** - Check server side variable 'license'. - - If the variable does not exist or does not contain 'Commercial', - we're talking to non-commercial server from commercial client. - - @retval 0 success - @retval !0 network error or the server is not commercial. - Error code is saved in mysql->net.last_errno. -*/ - -static int check_license(MYSQL *mysql) -{ - MYSQL_ROW row; - MYSQL_RES *res; - NET *net= &mysql->net; - static const char query[]= "SELECT @@license"; - static const char required_license[]= STRINGIFY_ARG(LICENSE); - - if (mysql_real_query(mysql, query, sizeof(query)-1)) - { - if (net->last_errno == ER_UNKNOWN_SYSTEM_VARIABLE) - { - set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate, - ER(CR_WRONG_LICENSE), required_license); - } - return 1; - } - if (!(res= mysql_use_result(mysql))) - return 1; - row= mysql_fetch_row(res); - /* - If no rows in result set, or column value is NULL (none of these - two is ever true for server variables now), or column value - mismatch, set wrong license error. - */ - if (!net->last_errno && - (!row || !row[0] || - strncmp(row[0], required_license, sizeof(required_license)))) - { - set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate, - ER(CR_WRONG_LICENSE), required_license); - } - mysql_free_result(res); - return net->last_errno; -} -#endif /* CHECK_LICENSE */ - - -/************************************************************************** - Shut down connection -**************************************************************************/ - -void end_server(MYSQL *mysql) -{ - int save_errno= errno; - DBUG_ENTER("end_server"); - if (mysql->net.vio != 0) - { - init_sigpipe_variables - DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio))); - set_sigpipe(mysql); - vio_delete(mysql->net.vio); - reset_sigpipe(mysql); - mysql->net.vio= 0; /* Marker */ - } - net_end(&mysql->net); - free_old_query(mysql); - errno= save_errno; - DBUG_VOID_RETURN; -} - - -void STDCALL -mysql_free_result(MYSQL_RES *result) -{ - DBUG_ENTER("mysql_free_result"); - DBUG_PRINT("enter",("mysql_res: %p", result)); - if (result) - { - MYSQL *mysql= result->handle; - if (mysql) - { - if (mysql->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled) - mysql->unbuffered_fetch_owner= 0; - if (mysql->status == MYSQL_STATUS_USE_RESULT) - { - (*mysql->methods->flush_use_result)(mysql, FALSE); - mysql->status=MYSQL_STATUS_READY; - if (mysql->unbuffered_fetch_owner) - *mysql->unbuffered_fetch_owner= TRUE; - } - } - free_rows(result->data); - if (result->fields) - free_root(&result->field_alloc,MYF(0)); - if (result->row) - my_free((uchar*) result->row,MYF(0)); - my_free((uchar*) result,MYF(0)); - } - DBUG_VOID_RETURN; -} - -/**************************************************************************** - Get options from my.cnf -****************************************************************************/ - -static const char *default_options[]= -{ - "port","socket","compress","password","pipe", "timeout", "user", - "init-command", "host", "database", "debug", "return-found-rows", - "ssl-key" ,"ssl-cert" ,"ssl-ca" ,"ssl-capath", - "character-sets-dir", "default-character-set", "interactive-timeout", - "connect-timeout", "local-infile", "disable-local-infile", - "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name", - "multi-results", "multi-statements", "multi-queries", "secure-auth", - "report-data-truncation", - NullS -}; - -static TYPELIB option_types={array_elements(default_options)-1, - "options",default_options, NULL}; - -const char *sql_protocol_names_lib[] = -{ "TCP", "SOCKET", "PIPE", "MEMORY", NullS }; -TYPELIB sql_protocol_typelib = {array_elements(sql_protocol_names_lib)-1,"", - sql_protocol_names_lib, NULL}; - -static int add_init_command(struct st_mysql_options *options, const char *cmd) -{ - char *tmp; - - if (!options->init_commands) - { - options->init_commands= (DYNAMIC_ARRAY*)my_malloc(sizeof(DYNAMIC_ARRAY), - MYF(MY_WME)); - init_dynamic_array(options->init_commands,sizeof(char*),5,5 CALLER_INFO); - } - - if (!(tmp= my_strdup(cmd,MYF(MY_WME))) || - insert_dynamic(options->init_commands, (uchar*)&tmp)) - { - my_free(tmp, MYF(MY_ALLOW_ZERO_PTR)); - return 1; - } - - return 0; -} - -void mysql_read_default_options(struct st_mysql_options *options, - const char *filename,const char *group) -{ - int argc; - char *argv_buff[1],**argv; - const char *groups[3]; - DBUG_ENTER("mysql_read_default_options"); - DBUG_PRINT("enter",("file: %s group: %s",filename,group ? group :"NULL")); - - argc=1; argv=argv_buff; argv_buff[0]= (char*) "client"; - groups[0]= (char*) "client"; groups[1]= (char*) group; groups[2]=0; - - my_load_defaults(filename, groups, &argc, &argv, NULL); - if (argc != 1) /* If some default option */ - { - char **option=argv; - while (*++option) - { - if (option[0] == args_separator) /* skip arguments separator */ - continue; - /* DBUG_PRINT("info",("option: %s",option[0])); */ - if (option[0][0] == '-' && option[0][1] == '-') - { - char *end=strcend(*option,'='); - char *opt_arg=0; - if (*end) - { - opt_arg=end+1; - *end=0; /* Remove '=' */ - } - /* Change all '_' in variable name to '-' */ - for (end= *option ; *(end= strcend(end,'_')) ; ) - *end= '-'; - switch (find_type(*option+2,&option_types,2)) { - case 1: /* port */ - if (opt_arg) - options->port=atoi(opt_arg); - break; - case 2: /* socket */ - if (opt_arg) - { - my_free(options->unix_socket,MYF(MY_ALLOW_ZERO_PTR)); - options->unix_socket=my_strdup(opt_arg,MYF(MY_WME)); - } - break; - case 3: /* compress */ - options->compress=1; - options->client_flag|= CLIENT_COMPRESS; - break; - case 4: /* password */ - if (opt_arg) - { - my_free(options->password,MYF(MY_ALLOW_ZERO_PTR)); - options->password=my_strdup(opt_arg,MYF(MY_WME)); - } - break; - case 5: - options->protocol = MYSQL_PROTOCOL_PIPE; - case 20: /* connect_timeout */ - case 6: /* timeout */ - if (opt_arg) - options->connect_timeout=atoi(opt_arg); - break; - case 7: /* user */ - if (opt_arg) - { - my_free(options->user,MYF(MY_ALLOW_ZERO_PTR)); - options->user=my_strdup(opt_arg,MYF(MY_WME)); - } - break; - case 8: /* init-command */ - add_init_command(options,opt_arg); - break; - case 9: /* host */ - if (opt_arg) - { - my_free(options->host,MYF(MY_ALLOW_ZERO_PTR)); - options->host=my_strdup(opt_arg,MYF(MY_WME)); - } - break; - case 10: /* database */ - if (opt_arg) - { - my_free(options->db,MYF(MY_ALLOW_ZERO_PTR)); - options->db=my_strdup(opt_arg,MYF(MY_WME)); - } - break; - case 11: /* debug */ -#ifdef MYSQL_CLIENT - mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace"); - break; -#endif - case 12: /* return-found-rows */ - options->client_flag|=CLIENT_FOUND_ROWS; - break; -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - case 13: /* ssl_key */ - my_free(options->ssl_key, MYF(MY_ALLOW_ZERO_PTR)); - options->ssl_key = my_strdup(opt_arg, MYF(MY_WME)); - break; - case 14: /* ssl_cert */ - my_free(options->ssl_cert, MYF(MY_ALLOW_ZERO_PTR)); - options->ssl_cert = my_strdup(opt_arg, MYF(MY_WME)); - break; - case 15: /* ssl_ca */ - my_free(options->ssl_ca, MYF(MY_ALLOW_ZERO_PTR)); - options->ssl_ca = my_strdup(opt_arg, MYF(MY_WME)); - break; - case 16: /* ssl_capath */ - my_free(options->ssl_capath, MYF(MY_ALLOW_ZERO_PTR)); - options->ssl_capath = my_strdup(opt_arg, MYF(MY_WME)); - break; - case 23: /* ssl_cipher */ - my_free(options->ssl_cipher, MYF(MY_ALLOW_ZERO_PTR)); - options->ssl_cipher= my_strdup(opt_arg, MYF(MY_WME)); - break; -#else - case 13: /* Ignore SSL options */ - case 14: - case 15: - case 16: - case 23: - break; -#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ - case 17: /* charset-lib */ - my_free(options->charset_dir,MYF(MY_ALLOW_ZERO_PTR)); - options->charset_dir = my_strdup(opt_arg, MYF(MY_WME)); - break; - case 18: - my_free(options->charset_name,MYF(MY_ALLOW_ZERO_PTR)); - options->charset_name = my_strdup(opt_arg, MYF(MY_WME)); - break; - case 19: /* Interactive-timeout */ - options->client_flag|= CLIENT_INTERACTIVE; - break; - case 21: - if (!opt_arg || atoi(opt_arg) != 0) - options->client_flag|= CLIENT_LOCAL_FILES; - else - options->client_flag&= ~CLIENT_LOCAL_FILES; - break; - case 22: - options->client_flag&= ~CLIENT_LOCAL_FILES; - break; - case 24: /* max-allowed-packet */ - if (opt_arg) - options->max_allowed_packet= atoi(opt_arg); - break; - case 25: /* protocol */ - if ((options->protocol= find_type(opt_arg, - &sql_protocol_typelib,0)) <= 0) - { - fprintf(stderr, "Unknown option to protocol: %s\n", opt_arg); - exit(1); - } - break; - case 26: /* shared_memory_base_name */ -#ifdef HAVE_SMEM - if (options->shared_memory_base_name != def_shared_memory_base_name) - my_free(options->shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); - options->shared_memory_base_name=my_strdup(opt_arg,MYF(MY_WME)); -#endif - break; - case 27: /* multi-results */ - options->client_flag|= CLIENT_MULTI_RESULTS; - break; - case 28: /* multi-statements */ - case 29: /* multi-queries */ - options->client_flag|= CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS; - break; - case 30: /* secure-auth */ - options->secure_auth= TRUE; - break; - case 31: /* report-data-truncation */ - options->report_data_truncation= opt_arg ? test(atoi(opt_arg)) : 1; - break; - default: - DBUG_PRINT("warning",("unknown option: %s",option[0])); - } - } - } - } - free_defaults(argv); - DBUG_VOID_RETURN; -} - - -/************************************************************************** - Get column lengths of the current row - If one uses mysql_use_result, res->lengths contains the length information, - else the lengths are calculated from the offset between pointers. -**************************************************************************/ - -static void cli_fetch_lengths(ulong *to, MYSQL_ROW column, - unsigned int field_count) -{ - ulong *prev_length; - char *start=0; - MYSQL_ROW end; - - prev_length=0; /* Keep gcc happy */ - for (end=column + field_count + 1 ; column != end ; column++, to++) - { - if (!*column) - { - *to= 0; /* Null */ - continue; - } - if (start) /* Found end of prev string */ - *prev_length= (ulong) (*column-start-1); - start= *column; - prev_length= to; - } -} - -/*************************************************************************** - Change field rows to field structs -***************************************************************************/ - -MYSQL_FIELD * -unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, - my_bool default_value, uint server_capabilities) -{ - MYSQL_ROWS *row; - MYSQL_FIELD *field,*result; - ulong lengths[9]; /* Max of fields */ - DBUG_ENTER("unpack_fields"); - - field= result= (MYSQL_FIELD*) alloc_root(alloc, - (uint) sizeof(*field)*fields); - if (!result) - { - free_rows(data); /* Free old data */ - DBUG_RETURN(0); - } - bzero((char*) field, (uint) sizeof(MYSQL_FIELD)*fields); - if (server_capabilities & CLIENT_PROTOCOL_41) - { - /* server is 4.1, and returns the new field result format */ - for (row=data->data; row ; row = row->next,field++) - { - uchar *pos; - /* fields count may be wrong */ - DBUG_ASSERT((uint) (field - result) < fields); - cli_fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7); - field->catalog= strmake_root(alloc,(char*) row->data[0], lengths[0]); - field->db= strmake_root(alloc,(char*) row->data[1], lengths[1]); - field->table= strmake_root(alloc,(char*) row->data[2], lengths[2]); - field->org_table= strmake_root(alloc,(char*) row->data[3], lengths[3]); - field->name= strmake_root(alloc,(char*) row->data[4], lengths[4]); - field->org_name= strmake_root(alloc,(char*) row->data[5], lengths[5]); - - field->catalog_length= lengths[0]; - field->db_length= lengths[1]; - field->table_length= lengths[2]; - field->org_table_length= lengths[3]; - field->name_length= lengths[4]; - field->org_name_length= lengths[5]; - - /* Unpack fixed length parts */ - pos= (uchar*) row->data[6]; - field->charsetnr= uint2korr(pos); - field->length= (uint) uint4korr(pos+2); - field->type= (enum enum_field_types) pos[6]; - field->flags= uint2korr(pos+7); - field->decimals= (uint) pos[9]; - - if (INTERNAL_NUM_FIELD(field)) - field->flags|= NUM_FLAG; - if (default_value && row->data[7]) - { - field->def=strmake_root(alloc,(char*) row->data[7], lengths[7]); - field->def_length= lengths[7]; - } - else - field->def=0; - field->max_length= 0; - } - } -#ifndef DELETE_SUPPORT_OF_4_0_PROTOCOL - else - { - /* old protocol, for backward compatibility */ - for (row=data->data; row ; row = row->next,field++) - { - cli_fetch_lengths(&lengths[0], row->data, default_value ? 6 : 5); - field->org_table= field->table= strdup_root(alloc,(char*) row->data[0]); - field->name= strdup_root(alloc,(char*) row->data[1]); - field->length= (uint) uint3korr(row->data[2]); - field->type= (enum enum_field_types) (uchar) row->data[3][0]; - - field->catalog=(char*) ""; - field->db= (char*) ""; - field->catalog_length= 0; - field->db_length= 0; - field->org_table_length= field->table_length= lengths[0]; - field->name_length= lengths[1]; - - if (server_capabilities & CLIENT_LONG_FLAG) - { - field->flags= uint2korr(row->data[4]); - field->decimals=(uint) (uchar) row->data[4][2]; - } - else - { - field->flags= (uint) (uchar) row->data[4][0]; - field->decimals=(uint) (uchar) row->data[4][1]; - } - if (INTERNAL_NUM_FIELD(field)) - field->flags|= NUM_FLAG; - if (default_value && row->data[5]) - { - field->def=strdup_root(alloc,(char*) row->data[5]); - field->def_length= lengths[5]; - } - else - field->def=0; - field->max_length= 0; - } - } -#endif /* DELETE_SUPPORT_OF_4_0_PROTOCOL */ - free_rows(data); /* Free old data */ - DBUG_RETURN(result); -} - -/* Read all rows (fields or data) from server */ - -MYSQL_DATA *cli_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, - unsigned int fields) -{ - uint field; - ulong pkt_len; - ulong len; - uchar *cp; - char *to, *end_to; - MYSQL_DATA *result; - MYSQL_ROWS **prev_ptr,*cur; - NET *net = &mysql->net; - DBUG_ENTER("cli_read_rows"); - - if ((pkt_len= cli_safe_read(mysql)) == packet_error) - DBUG_RETURN(0); - if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), - MYF(MY_WME | MY_ZEROFILL)))) - { - set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); - DBUG_RETURN(0); - } - init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */ - result->alloc.min_malloc=sizeof(MYSQL_ROWS); - prev_ptr= &result->data; - result->rows=0; - result->fields=fields; - - /* - The last EOF packet is either a single 254 character or (in MySQL 4.1) - 254 followed by 1-7 status bytes. - - This doesn't conflict with normal usage of 254 which stands for a - string where the length of the string is 8 bytes. (see net_field_length()) - */ - - while (*(cp=net->read_pos) != 254 || pkt_len >= 8) - { - result->rows++; - if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc, - sizeof(MYSQL_ROWS))) || - !(cur->data= ((MYSQL_ROW) - alloc_root(&result->alloc, - (fields+1)*sizeof(char *)+pkt_len)))) - { - free_rows(result); - set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); - DBUG_RETURN(0); - } - *prev_ptr=cur; - prev_ptr= &cur->next; - to= (char*) (cur->data+fields+1); - end_to=to+pkt_len-1; - for (field=0 ; field < fields ; field++) - { - if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH) - { /* null field */ - cur->data[field] = 0; - } - else - { - cur->data[field] = to; - if (len > (ulong) (end_to - to)) - { - free_rows(result); - set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate); - DBUG_RETURN(0); - } - memcpy(to,(char*) cp,len); to[len]=0; - to+=len+1; - cp+=len; - if (mysql_fields) - { - if (mysql_fields[field].max_length < len) - mysql_fields[field].max_length=len; - } - } - } - cur->data[field]=to; /* End of last field */ - if ((pkt_len=cli_safe_read(mysql)) == packet_error) - { - free_rows(result); - DBUG_RETURN(0); - } - } - *prev_ptr=0; /* last pointer is null */ - if (pkt_len > 1) /* MySQL 4.1 protocol */ - { - mysql->warning_count= uint2korr(cp+1); - mysql->server_status= uint2korr(cp+3); - DBUG_PRINT("info",("status: %u warning_count: %u", - mysql->server_status, mysql->warning_count)); - } - DBUG_PRINT("exit", ("Got %lu rows", (ulong) result->rows)); - DBUG_RETURN(result); -} - -/* - Read one row. Uses packet buffer as storage for fields. - When next packet is read, the previous field values are destroyed -*/ - - -static int -read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) -{ - uint field; - ulong pkt_len,len; - uchar *pos, *prev_pos, *end_pos; - NET *net= &mysql->net; - - if ((pkt_len=cli_safe_read(mysql)) == packet_error) - return -1; - if (pkt_len <= 8 && net->read_pos[0] == 254) - { - if (pkt_len > 1) /* MySQL 4.1 protocol */ - { - mysql->warning_count= uint2korr(net->read_pos+1); - mysql->server_status= uint2korr(net->read_pos+3); - } - return 1; /* End of data */ - } - prev_pos= 0; /* allowed to write at packet[-1] */ - pos=net->read_pos; - end_pos=pos+pkt_len; - for (field=0 ; field < fields ; field++) - { - if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH) - { /* null field */ - row[field] = 0; - *lengths++=0; - } - else - { - if (len > (ulong) (end_pos - pos)) - { - set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate); - return -1; - } - row[field] = (char*) pos; - pos+=len; - *lengths++=len; - } - if (prev_pos) - *prev_pos=0; /* Terminate prev field */ - prev_pos=pos; - } - row[field]=(char*) prev_pos+1; /* End of last field */ - *prev_pos=0; /* Terminate last field */ - return 0; -} - - -/**************************************************************************** - Init MySQL structure or allocate one -****************************************************************************/ - -MYSQL * STDCALL -mysql_init(MYSQL *mysql) -{ - if (mysql_server_init(0, NULL, NULL)) - return 0; - if (!mysql) - { - if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL)))) - { - set_mysql_error(NULL, CR_OUT_OF_MEMORY, unknown_sqlstate); - return 0; - } - mysql->free_me=1; - } - else - bzero((char*) (mysql), sizeof(*(mysql))); - mysql->options.connect_timeout= CONNECT_TIMEOUT; - mysql->charset=default_client_charset_info; - strmov(mysql->net.sqlstate, not_error_sqlstate); - - /* - Only enable LOAD DATA INFILE by default if configured with - --enable-local-infile - */ - -#if defined(ENABLED_LOCAL_INFILE) && !defined(MYSQL_SERVER) - mysql->options.client_flag|= CLIENT_LOCAL_FILES; -#endif - -#ifdef HAVE_SMEM - mysql->options.shared_memory_base_name= (char*) def_shared_memory_base_name; -#endif - - mysql->options.methods_to_use= MYSQL_OPT_GUESS_CONNECTION; - mysql->options.report_data_truncation= TRUE; /* default */ - - /* - By default we don't reconnect because it could silently corrupt data (after - reconnection you potentially lose table locks, user variables, session - variables (transactions but they are specifically dealt with in - mysql_reconnect()). - This is a change: < 5.0.3 mysql->reconnect was set to 1 by default. - How this change impacts existing apps: - - existing apps which relyed on the default will see a behaviour change; - they will have to set reconnect=1 after mysql_real_connect(). - - existing apps which explicitely asked for reconnection (the only way they - could do it was by setting mysql.reconnect to 1 after mysql_real_connect()) - will not see a behaviour change. - - existing apps which explicitely asked for no reconnection - (mysql.reconnect=0) will not see a behaviour change. - */ - mysql->reconnect= 0; - - return mysql; -} - - -/* - 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)) - -my_bool STDCALL -mysql_ssl_set(MYSQL *mysql __attribute__((unused)) , - const char *key __attribute__((unused)), - const char *cert __attribute__((unused)), - const char *ca __attribute__((unused)), - const char *capath __attribute__((unused)), - const char *cipher __attribute__((unused))) -{ - DBUG_ENTER("mysql_ssl_set"); -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - mysql->options.ssl_key= strdup_if_not_null(key); - mysql->options.ssl_cert= strdup_if_not_null(cert); - mysql->options.ssl_ca= strdup_if_not_null(ca); - mysql->options.ssl_capath= strdup_if_not_null(capath); - mysql->options.ssl_cipher= strdup_if_not_null(cipher); -#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ - DBUG_RETURN(0); -} - - -/* - Free strings in the SSL structure and clear 'use_ssl' flag. - NB! Errors are not reported until you do mysql_real_connect. -*/ - -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - -static void -mysql_ssl_free(MYSQL *mysql __attribute__((unused))) -{ - struct st_VioSSLFd *ssl_fd= (struct st_VioSSLFd*) mysql->connector_fd; - DBUG_ENTER("mysql_ssl_free"); - - my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.ssl_cipher, MYF(MY_ALLOW_ZERO_PTR)); - if (ssl_fd) - SSL_CTX_free(ssl_fd->ssl_context); - my_free(mysql->connector_fd,MYF(MY_ALLOW_ZERO_PTR)); - mysql->options.ssl_key = 0; - mysql->options.ssl_cert = 0; - mysql->options.ssl_ca = 0; - mysql->options.ssl_capath = 0; - mysql->options.ssl_cipher= 0; - mysql->options.use_ssl = FALSE; - mysql->connector_fd = 0; - DBUG_VOID_RETURN; -} - -#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ - -/* - Return the SSL cipher (if any) used for current - connection to the server. - - SYNOPSYS - mysql_get_ssl_cipher() - mysql pointer to the mysql connection - -*/ - -const char * STDCALL -mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused))) -{ - DBUG_ENTER("mysql_get_ssl_cipher"); -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - if (mysql->net.vio && mysql->net.vio->ssl_arg) - DBUG_RETURN(SSL_get_cipher_name((SSL*)mysql->net.vio->ssl_arg)); -#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ - DBUG_RETURN(NULL); -} - - -/* - Check the server's (subject) Common Name against the - hostname we connected to - - SYNOPSIS - ssl_verify_server_cert() - vio pointer to a SSL connected vio - server_hostname name of the server that we connected to - - RETURN VALUES - 0 Success - 1 Failed to validate server - - */ - -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - -static int ssl_verify_server_cert(Vio *vio, const char* server_hostname) -{ - SSL *ssl; - X509 *server_cert; - char *cp1, *cp2; - char buf[256]; - DBUG_ENTER("ssl_verify_server_cert"); - DBUG_PRINT("enter", ("server_hostname: %s", server_hostname)); - - if (!(ssl= (SSL*)vio->ssl_arg)) - { - DBUG_PRINT("error", ("No SSL pointer found")); - DBUG_RETURN(1); - } - - if (!server_hostname) - { - DBUG_PRINT("error", ("No server hostname supplied")); - DBUG_RETURN(1); - } - - if (!(server_cert= SSL_get_peer_certificate(ssl))) - { - DBUG_PRINT("error", ("Could not get server certificate")); - DBUG_RETURN(1); - } - - /* - We already know that the certificate exchanged was valid; the SSL library - handled that. Now we need to verify that the contents of the certificate - are what we expect. - */ - - X509_NAME_oneline(X509_get_subject_name(server_cert), buf, sizeof(buf)); - X509_free (server_cert); - - DBUG_PRINT("info", ("hostname in cert: %s", buf)); - cp1= strstr(buf, "/CN="); - if (cp1) - { - cp1+= 4; /* Skip the "/CN=" that we found */ - /* Search for next / which might be the delimiter for email */ - cp2= strchr(cp1, '/'); - if (cp2) - *cp2= '\0'; - DBUG_PRINT("info", ("Server hostname in cert: %s", cp1)); - if (!strcmp(cp1, server_hostname)) - { - /* Success */ - DBUG_RETURN(0); - } - } - DBUG_PRINT("error", ("SSL certificate validation failure")); - DBUG_RETURN(1); -} - -#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ - - -/* - Note that the mysql argument must be initialized with mysql_init() - before calling mysql_real_connect ! -*/ - -static my_bool cli_read_query_result(MYSQL *mysql); -static MYSQL_RES *cli_use_result(MYSQL *mysql); - -static MYSQL_METHODS client_methods= -{ - cli_read_query_result, /* read_query_result */ - cli_advanced_command, /* advanced_command */ - cli_read_rows, /* read_rows */ - cli_use_result, /* use_result */ - cli_fetch_lengths, /* fetch_lengths */ - cli_flush_use_result /* flush_use_result */ -#ifndef MYSQL_SERVER - ,cli_list_fields, /* list_fields */ - cli_read_prepare_result, /* read_prepare_result */ - cli_stmt_execute, /* stmt_execute */ - cli_read_binary_rows, /* read_binary_rows */ - cli_unbuffered_fetch, /* unbuffered_fetch */ - NULL, /* free_embedded_thd */ - cli_read_statistics, /* read_statistics */ - cli_read_query_result, /* next_result */ - cli_read_change_user_result, /* read_change_user_result */ - cli_read_binary_rows /* read_rows_from_cursor */ -#endif -}; - -C_MODE_START -int mysql_init_character_set(MYSQL *mysql) -{ - const char *default_collation_name; - - /* Set character set */ - if (!mysql->options.charset_name) - { - default_collation_name= MYSQL_DEFAULT_COLLATION_NAME; - if (!(mysql->options.charset_name= - my_strdup(MYSQL_DEFAULT_CHARSET_NAME,MYF(MY_WME)))) - return 1; - } - else - default_collation_name= NULL; - - { - const char *save= charsets_dir; - if (mysql->options.charset_dir) - charsets_dir=mysql->options.charset_dir; - mysql->charset=get_charset_by_csname(mysql->options.charset_name, - MY_CS_PRIMARY, MYF(MY_WME)); - if (mysql->charset && default_collation_name) - { - CHARSET_INFO *collation; - if ((collation= - get_charset_by_name(default_collation_name, MYF(MY_WME)))) - { - if (!my_charset_same(mysql->charset, collation)) - { - my_printf_error(ER_UNKNOWN_ERROR, - "COLLATION %s is not valid for CHARACTER SET %s", - MYF(0), - default_collation_name, mysql->options.charset_name); - mysql->charset= NULL; - } - else - { - mysql->charset= collation; - } - } - else - mysql->charset= NULL; - } - charsets_dir= save; - } - - if (!mysql->charset) - { - if (mysql->options.charset_dir) - set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate, - ER(CR_CANT_READ_CHARSET), - mysql->options.charset_name, - mysql->options.charset_dir); - else - { - char cs_dir_name[FN_REFLEN]; - get_charsets_dir(cs_dir_name); - set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate, - ER(CR_CANT_READ_CHARSET), - mysql->options.charset_name, - cs_dir_name); - } - return 1; - } - return 0; -} -C_MODE_END - - -MYSQL * STDCALL -CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, - const char *passwd, const char *db, - uint port, const char *unix_socket,ulong client_flag) -{ - char buff[NAME_LEN+USERNAME_LENGTH+100]; - char *end,*host_info; - ulong pkt_length; - NET *net= &mysql->net; -#ifdef MYSQL_SERVER - thr_alarm_t alarmed; - ALARM alarm_buff; -#endif -#ifdef __WIN__ - HANDLE hPipe=INVALID_HANDLE_VALUE; -#endif -#ifdef HAVE_SYS_UN_H - struct sockaddr_un UNIXaddr; -#endif - init_sigpipe_variables - DBUG_ENTER("mysql_real_connect"); - LINT_INIT(host_info); - - DBUG_PRINT("enter",("host: %s db: %s user: %s", - host ? host : "(Null)", - db ? db : "(Null)", - user ? user : "(Null)")); - - /* Test whether we're already connected */ - if (net->vio) - { - set_mysql_error(mysql, CR_ALREADY_CONNECTED, unknown_sqlstate); - DBUG_RETURN(0); - } - - /* Don't give sigpipe errors if the client doesn't want them */ - set_sigpipe(mysql); - mysql->methods= &client_methods; - net->vio = 0; /* If something goes wrong */ - mysql->client_flag=0; /* For handshake */ - - /* use default options */ - if (mysql->options.my_cnf_file || mysql->options.my_cnf_group) - { - mysql_read_default_options(&mysql->options, - (mysql->options.my_cnf_file ? - mysql->options.my_cnf_file : "my"), - mysql->options.my_cnf_group); - my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR)); - mysql->options.my_cnf_file=mysql->options.my_cnf_group=0; - } - - /* Some empty-string-tests are done because of ODBC */ - if (!host || !host[0]) - host=mysql->options.host; - if (!user || !user[0]) - { - user=mysql->options.user; - if (!user) - user= ""; - } - if (!passwd) - { - passwd=mysql->options.password; -#if !defined(DONT_USE_MYSQL_PWD) && !defined(MYSQL_SERVER) - if (!passwd) - passwd=getenv("MYSQL_PWD"); /* get it from environment */ -#endif - if (!passwd) - passwd= ""; - } - if (!db || !db[0]) - db=mysql->options.db; - if (!port) - port=mysql->options.port; - if (!unix_socket) - unix_socket=mysql->options.unix_socket; - - mysql->server_status=SERVER_STATUS_AUTOCOMMIT; - - /* - Part 0: Grab a socket and connect it to the server - */ -#if defined(HAVE_SMEM) - 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. Clear the error from - create_shared_memory(). - */ - - net_clear_error(net); - } - else - { - mysql->options.protocol=MYSQL_PROTOCOL_MEMORY; - unix_socket = 0; - host=mysql->options.shared_memory_base_name; - my_snprintf(host_info=buff, sizeof(buff)-1, - ER(CR_SHARED_MEMORY_CONNECTION), host); - } - } -#endif /* HAVE_SMEM */ -#if defined(HAVE_SYS_UN_H) - if (!net->vio && - (!mysql->options.protocol || - mysql->options.protocol == MYSQL_PROTOCOL_SOCKET) && - (unix_socket || mysql_unix_port) && - (!host || !strcmp(host,LOCAL_HOST))) - { - my_socket sock= socket(AF_UNIX, SOCK_STREAM, 0); - if (sock == SOCKET_ERROR) - { - set_mysql_extended_error(mysql, CR_SOCKET_CREATE_ERROR, - unknown_sqlstate, - ER(CR_SOCKET_CREATE_ERROR), - socket_errno); - goto error; - } - - net->vio= vio_new(sock, VIO_TYPE_SOCKET, - VIO_LOCALHOST | VIO_BUFFERED_READ); - if (!net->vio) - { - DBUG_PRINT("error",("Unknow protocol %d ", mysql->options.protocol)); - set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate); - closesocket(sock); - 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)); - - bzero((char*) &UNIXaddr, sizeof(UNIXaddr)); - UNIXaddr.sun_family= AF_UNIX; - strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path)-1); - - 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)); - set_mysql_extended_error(mysql, CR_CONNECTION_ERROR, - unknown_sqlstate, - ER(CR_CONNECTION_ERROR), - unix_socket, socket_errno); - vio_delete(net->vio); - net->vio= 0; - goto error; - } - mysql->options.protocol=MYSQL_PROTOCOL_SOCKET; - } -#elif defined(__WIN__) - if (!net->vio && - (mysql->options.protocol == MYSQL_PROTOCOL_PIPE || - (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) || - (! have_tcpip && (unix_socket || !host && is_NT())))) - { - if ((hPipe= create_named_pipe(mysql, 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); - my_snprintf(host_info=buff, sizeof(buff)-1, - ER(CR_NAMEDPIPE_CONNECTION), unix_socket); - } - } -#endif - if (!net->vio && - (!mysql->options.protocol || - mysql->options.protocol == MYSQL_PROTOCOL_TCP)) - { - struct addrinfo *res_lst, hints, *t_res; - int gai_errno; - char port_buf[NI_MAXSERV]; - - unix_socket=0; /* This is not used */ - - if (!port) - port= mysql_port; - - if (!host) - host= LOCAL_HOST; - - my_snprintf(host_info=buff, sizeof(buff)-1, ER(CR_TCP_CONNECTION), host); - DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host, port)); -#ifdef MYSQL_SERVER - thr_alarm_init(&alarmed); - thr_alarm(&alarmed, mysql->options.connect_timeout, &alarm_buff); -#endif - - DBUG_PRINT("info",("IP '%s'", "client")); - -#ifdef MYSQL_SERVER - thr_end_alarm(&alarmed); -#endif - - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype= SOCK_STREAM; - hints.ai_protocol= IPPROTO_TCP; - hints.ai_family= AF_UNSPEC; - - DBUG_PRINT("info",("IPV6 getaddrinfo %s", host)); - my_snprintf(port_buf, NI_MAXSERV, "%d", port); - gai_errno= getaddrinfo(host, port_buf, &hints, &res_lst); - - if (gai_errno != 0) - { - /* - For DBUG we are keeping the right message but for client we default to - historical error message. - */ - DBUG_PRINT("info",("IPV6 getaddrinfo error %d", gai_errno)); - set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate, - ER(CR_UNKNOWN_HOST), host, errno); - - goto error; - } - - /* We only look at the first item (something to think about changing in the future) */ - t_res= res_lst; - { - my_socket sock= socket(t_res->ai_family, t_res->ai_socktype, - t_res->ai_protocol); - if (sock == SOCKET_ERROR) - { - set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate, - ER(CR_IPSOCK_ERROR), socket_errno); - freeaddrinfo(res_lst); - goto error; - } - - net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ); - if (! net->vio ) - { - DBUG_PRINT("error",("Unknow protocol %d ", mysql->options.protocol)); - set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate); - closesocket(sock); - freeaddrinfo(res_lst); - goto error; - } - - if (my_connect(sock, t_res->ai_addr, t_res->ai_addrlen, - mysql->options.connect_timeout)) - { - DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno, - host)); - set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate, - ER(CR_CONN_HOST_ERROR), host, socket_errno); - vio_delete(net->vio); - net->vio= 0; - freeaddrinfo(res_lst); - goto error; - } - } - - freeaddrinfo(res_lst); - } - - if (!net->vio) - { - DBUG_PRINT("error",("Unknow protocol %d ",mysql->options.protocol)); - set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate); - goto error; - } - - if (my_net_init(net, net->vio)) - { - vio_delete(net->vio); - net->vio = 0; - set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); - goto error; - } - vio_keepalive(net->vio,TRUE); - - /* If user set read_timeout, let it override the default */ - if (mysql->options.read_timeout) - my_net_set_read_timeout(net, mysql->options.read_timeout); - - /* If user set write_timeout, let it override the default */ - if (mysql->options.write_timeout) - my_net_set_write_timeout(net, mysql->options.write_timeout); - - if (mysql->options.max_allowed_packet) - net->max_packet_size= mysql->options.max_allowed_packet; - - /* Get version info */ - mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */ - if (mysql->options.connect_timeout && - vio_poll_read(net->vio, mysql->options.connect_timeout)) - { - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "waiting for initial communication packet", - errno); - goto error; - } - - /* - Part 1: Connection established, read and parse first packet - */ - - if ((pkt_length=cli_safe_read(mysql)) == packet_error) - { - if (mysql->net.last_errno == CR_SERVER_LOST) - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "reading initial communication packet", - errno); - goto error; - } - /* Check if version of protocol matches current one */ - - mysql->protocol_version= net->read_pos[0]; - DBUG_DUMP("packet",(uchar*) net->read_pos,10); - DBUG_PRINT("info",("mysql protocol version %d, server=%d", - PROTOCOL_VERSION, mysql->protocol_version)); - if (mysql->protocol_version != PROTOCOL_VERSION) - { - set_mysql_extended_error(mysql, CR_VERSION_ERROR, unknown_sqlstate, - ER(CR_VERSION_ERROR), mysql->protocol_version, - PROTOCOL_VERSION); - goto error; - } - end=strend((char*) net->read_pos+1); - mysql->thread_id=uint4korr(end+1); - end+=5; - /* - Scramble is split into two parts because old clients does not understand - long scrambles; here goes the first part. - */ - strmake(mysql->scramble, end, SCRAMBLE_LENGTH_323); - end+= SCRAMBLE_LENGTH_323+1; - - if (pkt_length >= (uint) (end+1 - (char*) net->read_pos)) - mysql->server_capabilities=uint2korr(end); - if (pkt_length >= (uint) (end+18 - (char*) net->read_pos)) - { - /* New protocol with 16 bytes to describe server characteristics */ - mysql->server_language=end[2]; - mysql->server_status=uint2korr(end+3); - } - end+= 18; - if (pkt_length >= (uint) (end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1 - - (char *) net->read_pos)) - strmake(mysql->scramble+SCRAMBLE_LENGTH_323, end, - SCRAMBLE_LENGTH-SCRAMBLE_LENGTH_323); - else - mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION; - - if (mysql->options.secure_auth && passwd[0] && - !(mysql->server_capabilities & CLIENT_SECURE_CONNECTION)) - { - set_mysql_error(mysql, CR_SECURE_AUTH, unknown_sqlstate); - goto error; - } - - if (mysql_init_character_set(mysql)) - goto error; - - /* Save connection information */ - if (!my_multi_malloc(MYF(0), - &mysql->host_info, (uint) strlen(host_info)+1, - &mysql->host, (uint) strlen(host)+1, - &mysql->unix_socket,unix_socket ? - (uint) strlen(unix_socket)+1 : (uint) 1, - &mysql->server_version, - (uint) (end - (char*) net->read_pos), - NullS) || - !(mysql->user=my_strdup(user,MYF(0))) || - !(mysql->passwd=my_strdup(passwd,MYF(0)))) - { - set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); - goto error; - } - strmov(mysql->host_info,host_info); - strmov(mysql->host,host); - if (unix_socket) - strmov(mysql->unix_socket,unix_socket); - else - mysql->unix_socket=0; - strmov(mysql->server_version,(char*) net->read_pos+1); - mysql->port=port; - - /* - Part 2: format and send client info to the server for access check - */ - - client_flag|=mysql->options.client_flag; - client_flag|=CLIENT_CAPABILITIES; - if (client_flag & CLIENT_MULTI_STATEMENTS) - client_flag|= CLIENT_MULTI_RESULTS; - -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - if (mysql->options.ssl_key || mysql->options.ssl_cert || - mysql->options.ssl_ca || mysql->options.ssl_capath || - mysql->options.ssl_cipher) - mysql->options.use_ssl= 1; - if (mysql->options.use_ssl) - client_flag|=CLIENT_SSL; -#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/ - if (db) - 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_flag & mysql->server_capabilities)); -#ifndef HAVE_COMPRESS - client_flag&= ~CLIENT_COMPRESS; -#endif - - if (client_flag & CLIENT_PROTOCOL_41) - { - /* 4.1 server and 4.1 client has a 32 byte option flag */ - int4store(buff,client_flag); - int4store(buff+4, net->max_packet_size); - buff[8]= (char) mysql->charset->number; - /* - Character set 45 (4-byte UTF-8) is not available on servers - before version 6.0, so we need to go ahead and switch to utf8_mb3. - */ - if (mysql->charset->number == 45 && mysql->server_version[0] < '6') - buff[8]= 33; - else - buff[8]= (char)mysql->charset->number; - - bzero(buff+9, 32-9); - end= buff+32; - } - else - { - int2store(buff,client_flag); - int3store(buff+2,net->max_packet_size); - end= buff+5; - } - mysql->client_flag=client_flag; - -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - if (client_flag & CLIENT_SSL) - { - /* Do the SSL layering. */ - struct st_mysql_options *options= &mysql->options; - struct st_VioSSLFd *ssl_fd; - - /* - Send client_flag, max_packet_size - unencrypted otherwise - the server does not know we want to do SSL - */ - if (my_net_write(net, (uchar*) buff, (uint) (end-buff)) || net_flush(net)) - { - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "sending connection information to server", - errno); - goto error; - } - - /* Create the VioSSLConnectorFd - init SSL and load certs */ - if (!(ssl_fd= new_VioSSLConnectorFd(options->ssl_key, - options->ssl_cert, - options->ssl_ca, - options->ssl_capath, - options->ssl_cipher))) - { - set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); - goto error; - } - mysql->connector_fd= (void*)ssl_fd; - - /* Connect to the server */ - DBUG_PRINT("info", ("IO layer change in progress...")); - if (sslconnect(ssl_fd, mysql->net.vio, - (long) (mysql->options.connect_timeout))) - { - set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); - goto error; - } - DBUG_PRINT("info", ("IO layer change done!")); - - /* Verify server cert */ - if ((client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) && - ssl_verify_server_cert(mysql->net.vio, mysql->host)) - { - set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); - goto error; - } - - } -#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ - - DBUG_PRINT("info",("Server version = '%s' capabilites: %lu status: %u client_flag: %lu", - mysql->server_version,mysql->server_capabilities, - mysql->server_status, client_flag)); - /* This needs to be changed as it's not useful with big packets */ - if (user && user[0]) - strmake(end,user,USERNAME_LENGTH); /* Max user name */ - else - read_user_name((char*) end); - - /* We have to handle different version of handshake here */ -#ifdef _CUSTOMCONFIG_ -#include "_cust_libmysql.h" -#endif - DBUG_PRINT("info",("user: %s",end)); - end= strend(end) + 1; - if (passwd[0]) - { - if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) - { - *end++= SCRAMBLE_LENGTH; - scramble(end, mysql->scramble, passwd); - end+= SCRAMBLE_LENGTH; - } - else - { - scramble_323(end, mysql->scramble, passwd); - end+= SCRAMBLE_LENGTH_323 + 1; - } - } - else - *end++= '\0'; /* empty password */ - - /* Add database if needed */ - if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB)) - { - end= strmake(end, db, NAME_LEN) + 1; - mysql->db= my_strdup(db,MYF(MY_WME)); - db= 0; - } - /* Write authentication package */ - if (my_net_write(net, (uchar*) buff, (size_t) (end-buff)) || net_flush(net)) - { - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "sending authentication information", - errno); - goto error; - } - - /* - Part 3: Authorization data's been sent. Now server can reply with - OK-packet, or re-request scrambled password. - */ - - if ((pkt_length=cli_safe_read(mysql)) == packet_error) - { - if (mysql->net.last_errno == CR_SERVER_LOST) - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "reading authorization packet", - errno); - goto error; - } - - if (pkt_length == 1 && net->read_pos[0] == 254 && - mysql->server_capabilities & CLIENT_SECURE_CONNECTION) - { - /* - By sending this very specific reply server asks us to send scrambled - password in old format. - */ - scramble_323(buff, mysql->scramble, passwd); - if (my_net_write(net, (uchar*) buff, SCRAMBLE_LENGTH_323 + 1) || - net_flush(net)) - { - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "sending password information", - errno); - goto error; - } - /* Read what server thinks about out new auth message report */ - if (cli_safe_read(mysql) == packet_error) - { - if (mysql->net.last_errno == CR_SERVER_LOST) - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "reading final connect information", - errno); - goto error; - } - } - - if (client_flag & CLIENT_COMPRESS) /* We will use compression */ - net->compress=1; - -#ifdef CHECK_LICENSE - if (check_license(mysql)) - goto error; -#endif - - if (db && mysql_select_db(mysql, db)) - { - if (mysql->net.last_errno == CR_SERVER_LOST) - set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, - ER(CR_SERVER_LOST_EXTENDED), - "Setting intital database", - errno); - goto error; - } - - if (mysql->options.init_commands) - { - DYNAMIC_ARRAY *init_commands= mysql->options.init_commands; - char **ptr= (char**)init_commands->buffer; - char **end_command= ptr + init_commands->elements; - - my_bool reconnect=mysql->reconnect; - mysql->reconnect=0; - - for (; ptr < end_command; ptr++) - { - MYSQL_RES *res; - if (mysql_real_query(mysql,*ptr, (ulong) strlen(*ptr))) - goto error; - if (mysql->fields) - { - if (!(res= cli_use_result(mysql))) - goto error; - mysql_free_result(res); - } - } - mysql->reconnect=reconnect; - } - - DBUG_PRINT("exit", ("Mysql handler: %p", mysql)); - reset_sigpipe(mysql); - DBUG_RETURN(mysql); - -error: - reset_sigpipe(mysql); - DBUG_PRINT("error",("message: %u/%s (%s)", - net->last_errno, - net->sqlstate, - net->last_error)); - { - /* Free alloced memory */ - end_server(mysql); - mysql_close_free(mysql); - if (!(((ulong) client_flag) & CLIENT_REMEMBER_OPTIONS)) - mysql_close_free_options(mysql); - } - DBUG_RETURN(0); -} - - -my_bool mysql_reconnect(MYSQL *mysql) -{ - MYSQL tmp_mysql; - DBUG_ENTER("mysql_reconnect"); - DBUG_ASSERT(mysql); - DBUG_PRINT("enter", ("mysql->reconnect: %d", mysql->reconnect)); - - if (!mysql->reconnect || - (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info) - { - /* Allow reconnect next time */ - mysql->server_status&= ~SERVER_STATUS_IN_TRANS; - set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate); - DBUG_RETURN(1); - } - mysql_init(&tmp_mysql); - tmp_mysql.options= mysql->options; - tmp_mysql.options.my_cnf_file= tmp_mysql.options.my_cnf_group= 0; - - if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd, - mysql->db, mysql->port, mysql->unix_socket, - mysql->client_flag | CLIENT_REMEMBER_OPTIONS)) - { - mysql->net.last_errno= tmp_mysql.net.last_errno; - strmov(mysql->net.last_error, tmp_mysql.net.last_error); - strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate); - DBUG_RETURN(1); - } - if (mysql_set_character_set(&tmp_mysql, mysql->charset->csname)) - { - DBUG_PRINT("error", ("mysql_set_character_set() failed")); - bzero((char*) &tmp_mysql.options,sizeof(tmp_mysql.options)); - mysql_close(&tmp_mysql); - mysql->net.last_errno= tmp_mysql.net.last_errno; - strmov(mysql->net.last_error, tmp_mysql.net.last_error); - strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate); - DBUG_RETURN(1); - } - - DBUG_PRINT("info", ("reconnect succeded")); - tmp_mysql.reconnect= 1; - tmp_mysql.free_me= mysql->free_me; - - /* - For each stmt in mysql->stmts, move it to tmp_mysql if it is - in state MYSQL_STMT_INIT_DONE, otherwise close it. - */ - { - LIST *element= mysql->stmts; - for (; element; element= element->next) - { - MYSQL_STMT *stmt= (MYSQL_STMT *) element->data; - if (stmt->state != MYSQL_STMT_INIT_DONE) - { - stmt->mysql= 0; - stmt->last_errno= CR_SERVER_LOST; - strmov(stmt->last_error, ER(CR_SERVER_LOST)); - strmov(stmt->sqlstate, unknown_sqlstate); - } - else - { - tmp_mysql.stmts= list_add(tmp_mysql.stmts, &stmt->list); - } - /* No need to call list_delete for statement here */ - } - mysql->stmts= NULL; - } - - /* Don't free options as these are now used in tmp_mysql */ - bzero((char*) &mysql->options,sizeof(mysql->options)); - mysql->free_me=0; - mysql_close(mysql); - *mysql=tmp_mysql; - net_clear(&mysql->net, 1); - mysql->affected_rows= ~(my_ulonglong) 0; - DBUG_RETURN(0); -} - - -/************************************************************************** - Set current database -**************************************************************************/ - -int STDCALL -mysql_select_db(MYSQL *mysql, const char *db) -{ - int error; - DBUG_ENTER("mysql_select_db"); - DBUG_PRINT("enter",("db: '%s'",db)); - - if ((error=simple_command(mysql,COM_INIT_DB, (const uchar*) db, - (ulong) strlen(db),0))) - DBUG_RETURN(error); - my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR)); - mysql->db=my_strdup(db,MYF(MY_WME)); - DBUG_RETURN(0); -} - - -/************************************************************************* - Send a QUIT to the server and close the connection - If handle is alloced by mysql connect free it. -*************************************************************************/ - -static void mysql_close_free_options(MYSQL *mysql) -{ - DBUG_ENTER("mysql_close_free_options"); - - my_free(mysql->options.user,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.host,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.password,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.unix_socket,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.db,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.client_ip,MYF(MY_ALLOW_ZERO_PTR)); - if (mysql->options.init_commands) - { - DYNAMIC_ARRAY *init_commands= mysql->options.init_commands; - char **ptr= (char**)init_commands->buffer; - char **end= ptr + init_commands->elements; - for (; ptr<end; ptr++) - my_free(*ptr,MYF(MY_WME)); - delete_dynamic(init_commands); - my_free((char*)init_commands,MYF(MY_WME)); - } -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - mysql_ssl_free(mysql); -#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ -#ifdef HAVE_SMEM - if (mysql->options.shared_memory_base_name != def_shared_memory_base_name) - my_free(mysql->options.shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); -#endif /* HAVE_SMEM */ - bzero((char*) &mysql->options,sizeof(mysql->options)); - DBUG_VOID_RETURN; -} - - -static void mysql_close_free(MYSQL *mysql) -{ - my_free((uchar*) mysql->host_info,MYF(MY_ALLOW_ZERO_PTR)); - 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)); -#if defined(EMBEDDED_LIBRARY) || MYSQL_VERSION_ID >= 50100 - my_free(mysql->info_buffer,MYF(MY_ALLOW_ZERO_PTR)); - mysql->info_buffer= 0; -#endif - /* Clear pointers for better safety */ - mysql->host_info= mysql->user= mysql->passwd= mysql->db= 0; -} - - -/* - Clear connection pointer of every statement: this is necessary - to give error on attempt to use a prepared statement of closed - connection. - - SYNOPSYS - mysql_detach_stmt_list() - stmt_list pointer to mysql->stmts - func_name name of calling function - - NOTE - There is similar code in mysql_reconnect(), so changes here - should also be reflected there. -*/ - -void mysql_detach_stmt_list(LIST **stmt_list __attribute__((unused)), - const char *func_name __attribute__((unused))) -{ -#ifdef MYSQL_CLIENT - /* Reset connection handle in all prepared statements. */ - LIST *element= *stmt_list; - char buff[MYSQL_ERRMSG_SIZE]; - DBUG_ENTER("mysql_detach_stmt_list"); - - my_snprintf(buff, sizeof(buff)-1, ER(CR_STMT_CLOSED), func_name); - for (; element; element= element->next) - { - MYSQL_STMT *stmt= (MYSQL_STMT *) element->data; - set_stmt_error(stmt, CR_STMT_CLOSED, unknown_sqlstate, buff); - stmt->mysql= 0; - /* No need to call list_delete for statement here */ - } - *stmt_list= 0; - DBUG_VOID_RETURN; -#endif /* MYSQL_CLIENT */ -} - - -void STDCALL mysql_close(MYSQL *mysql) -{ - DBUG_ENTER("mysql_close"); - if (mysql) /* Some simple safety */ - { - /* If connection is still up, send a QUIT message */ - if (mysql->net.vio != 0) - { - free_old_query(mysql); - mysql->status=MYSQL_STATUS_READY; /* Force command */ - mysql->reconnect=0; - simple_command(mysql,COM_QUIT,(uchar*) 0,0,1); - end_server(mysql); /* Sets mysql->net.vio= 0 */ - } - mysql_close_free_options(mysql); - mysql_close_free(mysql); - mysql_detach_stmt_list(&mysql->stmts, "mysql_close"); -#ifndef MYSQL_SERVER - if (mysql->thd) - (*mysql->methods->free_embedded_thd)(mysql); -#endif - if (mysql->free_me) - my_free((uchar*) mysql,MYF(0)); - } - DBUG_VOID_RETURN; -} - - -static my_bool cli_read_query_result(MYSQL *mysql) -{ - uchar *pos; - ulong field_count; - MYSQL_DATA *fields; - ulong length; - DBUG_ENTER("cli_read_query_result"); - - if ((length = cli_safe_read(mysql)) == packet_error) - DBUG_RETURN(1); - free_old_query(mysql); /* Free old result */ -#ifdef MYSQL_CLIENT /* Avoid warn of unused labels*/ -get_info: -#endif - pos=(uchar*) mysql->net.read_pos; - if ((field_count= net_field_length(&pos)) == 0) - { - mysql->affected_rows= net_field_length_ll(&pos); - mysql->insert_id= net_field_length_ll(&pos); - DBUG_PRINT("info",("affected_rows: %lu insert_id: %lu", - (ulong) mysql->affected_rows, - (ulong) mysql->insert_id)); - if (protocol_41(mysql)) - { - mysql->server_status=uint2korr(pos); pos+=2; - mysql->warning_count=uint2korr(pos); pos+=2; - } - else if (mysql->server_capabilities & CLIENT_TRANSACTIONS) - { - /* MySQL 4.0 protocol */ - mysql->server_status=uint2korr(pos); pos+=2; - mysql->warning_count= 0; - } - DBUG_PRINT("info",("status: %u warning_count: %u", - mysql->server_status, mysql->warning_count)); - if (pos < mysql->net.read_pos+length && net_field_length(&pos)) - mysql->info=(char*) pos; - DBUG_RETURN(0); - } -#ifdef MYSQL_CLIENT - if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */ - { - int error; - - if (!(mysql->options.client_flag & CLIENT_LOCAL_FILES)) - { - set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate); - DBUG_RETURN(1); - } - - error= handle_local_infile(mysql,(char*) pos); - if ((length= cli_safe_read(mysql)) == packet_error || error) - DBUG_RETURN(1); - goto get_info; /* Get info packet */ - } -#endif - if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT)) - mysql->server_status|= SERVER_STATUS_IN_TRANS; - - if (!(fields=cli_read_rows(mysql,(MYSQL_FIELD*)0, protocol_41(mysql) ? 7:5))) - DBUG_RETURN(1); - if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc, - (uint) field_count,0, - mysql->server_capabilities))) - DBUG_RETURN(1); - mysql->status= MYSQL_STATUS_GET_RESULT; - mysql->field_count= (uint) field_count; - DBUG_PRINT("exit",("ok")); - DBUG_RETURN(0); -} - - -/* - Send the query and return so we can do something else. - Needs to be followed by mysql_read_query_result() when we want to - finish processing it. -*/ - -int STDCALL -mysql_send_query(MYSQL* mysql, const char* query, ulong length) -{ - DBUG_ENTER("mysql_send_query"); - DBUG_RETURN(simple_command(mysql, COM_QUERY, (uchar*) query, length, 1)); -} - - -int STDCALL -mysql_real_query(MYSQL *mysql, const char *query, ulong length) -{ - DBUG_ENTER("mysql_real_query"); - DBUG_PRINT("enter",("handle: %p", mysql)); - DBUG_PRINT("query",("Query = '%-.4096s'",query)); - - if (mysql_send_query(mysql,query,length)) - DBUG_RETURN(1); - DBUG_RETURN((int) (*mysql->methods->read_query_result)(mysql)); -} - - -/************************************************************************** - Alloc result struct for buffered results. All rows are read to buffer. - mysql_data_seek may be used. -**************************************************************************/ - -MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql) -{ - MYSQL_RES *result; - DBUG_ENTER("mysql_store_result"); - - if (!mysql->fields) - DBUG_RETURN(0); - if (mysql->status != MYSQL_STATUS_GET_RESULT) - { - set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); - DBUG_RETURN(0); - } - mysql->status=MYSQL_STATUS_READY; /* server is ready */ - if (!(result=(MYSQL_RES*) my_malloc((uint) (sizeof(MYSQL_RES)+ - sizeof(ulong) * - mysql->field_count), - MYF(MY_WME | MY_ZEROFILL)))) - { - set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); - DBUG_RETURN(0); - } - result->methods= mysql->methods; - result->eof=1; /* Marker for buffered */ - result->lengths=(ulong*) (result+1); - if (!(result->data= - (*mysql->methods->read_rows)(mysql,mysql->fields,mysql->field_count))) - { - my_free((uchar*) result,MYF(0)); - DBUG_RETURN(0); - } - mysql->affected_rows= result->row_count= result->data->rows; - result->data_cursor= result->data->data; - result->fields= mysql->fields; - result->field_alloc= mysql->field_alloc; - result->field_count= mysql->field_count; - /* The rest of result members is bzeroed in malloc */ - mysql->fields=0; /* fields is now in result */ - clear_alloc_root(&mysql->field_alloc); - /* just in case this was mistakenly called after mysql_stmt_execute() */ - mysql->unbuffered_fetch_owner= 0; - DBUG_RETURN(result); /* Data fetched */ -} - - -/************************************************************************** - Alloc struct for use with unbuffered reads. Data is fetched by domand - when calling to mysql_fetch_row. - mysql_data_seek is a noop. - - No other queries may be specified with the same MYSQL handle. - There shouldn't be much processing per row because mysql server shouldn't - have to wait for the client (and will not wait more than 30 sec/packet). -**************************************************************************/ - -static MYSQL_RES * cli_use_result(MYSQL *mysql) -{ - MYSQL_RES *result; - DBUG_ENTER("cli_use_result"); - - if (!mysql->fields) - DBUG_RETURN(0); - if (mysql->status != MYSQL_STATUS_GET_RESULT) - { - set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); - DBUG_RETURN(0); - } - if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+ - sizeof(ulong)*mysql->field_count, - MYF(MY_WME | MY_ZEROFILL)))) - DBUG_RETURN(0); - result->lengths=(ulong*) (result+1); - result->methods= mysql->methods; - if (!(result->row=(MYSQL_ROW) - my_malloc(sizeof(result->row[0])*(mysql->field_count+1), MYF(MY_WME)))) - { /* Ptrs: to one row */ - my_free((uchar*) result,MYF(0)); - DBUG_RETURN(0); - } - result->fields= mysql->fields; - result->field_alloc= mysql->field_alloc; - result->field_count= mysql->field_count; - result->current_field=0; - result->handle= mysql; - result->current_row= 0; - mysql->fields=0; /* fields is now in result */ - clear_alloc_root(&mysql->field_alloc); - mysql->status=MYSQL_STATUS_USE_RESULT; - mysql->unbuffered_fetch_owner= &result->unbuffered_fetch_cancelled; - DBUG_RETURN(result); /* Data is read to be fetched */ -} - - -/************************************************************************** - Return next row of the query results -**************************************************************************/ - -MYSQL_ROW STDCALL -mysql_fetch_row(MYSQL_RES *res) -{ - DBUG_ENTER("mysql_fetch_row"); - if (!res->data) - { /* Unbufferred fetch */ - if (!res->eof) - { - MYSQL *mysql= res->handle; - if (mysql->status != MYSQL_STATUS_USE_RESULT) - { - set_mysql_error(mysql, - res->unbuffered_fetch_cancelled ? - CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC, - unknown_sqlstate); - } - else if (!(read_one_row(mysql, res->field_count, res->row, res->lengths))) - { - res->row_count++; - DBUG_RETURN(res->current_row=res->row); - } - DBUG_PRINT("info",("end of data")); - res->eof=1; - mysql->status=MYSQL_STATUS_READY; - /* - Reset only if owner points to us: there is a chance that somebody - started new query after mysql_stmt_close(): - */ - if (mysql->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled) - mysql->unbuffered_fetch_owner= 0; - /* Don't clear handle in mysql_free_result */ - res->handle=0; - } - DBUG_RETURN((MYSQL_ROW) NULL); - } - { - MYSQL_ROW tmp; - if (!res->data_cursor) - { - DBUG_PRINT("info",("end of data")); - DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL); - } - tmp = res->data_cursor->data; - res->data_cursor = res->data_cursor->next; - DBUG_RETURN(res->current_row=tmp); - } -} - - -/************************************************************************** - Get column lengths of the current row - If one uses mysql_use_result, res->lengths contains the length information, - else the lengths are calculated from the offset between pointers. -**************************************************************************/ - -ulong * STDCALL -mysql_fetch_lengths(MYSQL_RES *res) -{ - MYSQL_ROW column; - - if (!(column=res->current_row)) - return 0; /* Something is wrong */ - if (res->data) - (*res->methods->fetch_lengths)(res->lengths, column, res->field_count); - return res->lengths; -} - - -int STDCALL -mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg) -{ - DBUG_ENTER("mysql_option"); - DBUG_PRINT("enter",("option: %d",(int) option)); - switch (option) { - case MYSQL_OPT_CONNECT_TIMEOUT: - mysql->options.connect_timeout= *(uint*) arg; - break; - case MYSQL_OPT_READ_TIMEOUT: - mysql->options.read_timeout= *(uint*) arg; - break; - case MYSQL_OPT_WRITE_TIMEOUT: - mysql->options.write_timeout= *(uint*) arg; - break; - case MYSQL_OPT_COMPRESS: - mysql->options.compress= 1; /* Remember for connect */ - mysql->options.client_flag|= CLIENT_COMPRESS; - break; - case MYSQL_OPT_NAMED_PIPE: /* This option is depricated */ - mysql->options.protocol=MYSQL_PROTOCOL_PIPE; /* Force named pipe */ - break; - case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/ - if (!arg || test(*(uint*) arg)) - mysql->options.client_flag|= CLIENT_LOCAL_FILES; - else - mysql->options.client_flag&= ~CLIENT_LOCAL_FILES; - break; - case MYSQL_INIT_COMMAND: - add_init_command(&mysql->options,arg); - break; - case MYSQL_READ_DEFAULT_FILE: - my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR)); - mysql->options.my_cnf_file=my_strdup(arg,MYF(MY_WME)); - break; - case MYSQL_READ_DEFAULT_GROUP: - my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR)); - mysql->options.my_cnf_group=my_strdup(arg,MYF(MY_WME)); - break; - case MYSQL_SET_CHARSET_DIR: - my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR)); - mysql->options.charset_dir=my_strdup(arg,MYF(MY_WME)); - break; - case MYSQL_SET_CHARSET_NAME: - my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR)); - mysql->options.charset_name=my_strdup(arg,MYF(MY_WME)); - break; - case MYSQL_OPT_PROTOCOL: - mysql->options.protocol= *(uint*) arg; - break; - case MYSQL_SHARED_MEMORY_BASE_NAME: -#ifdef HAVE_SMEM - if (mysql->options.shared_memory_base_name != def_shared_memory_base_name) - my_free(mysql->options.shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); - mysql->options.shared_memory_base_name=my_strdup(arg,MYF(MY_WME)); -#endif - break; - case MYSQL_OPT_USE_REMOTE_CONNECTION: - case MYSQL_OPT_USE_EMBEDDED_CONNECTION: - case MYSQL_OPT_GUESS_CONNECTION: - mysql->options.methods_to_use= option; - break; - case MYSQL_SET_CLIENT_IP: - mysql->options.client_ip= my_strdup(arg, MYF(MY_WME)); - break; - case MYSQL_SECURE_AUTH: - mysql->options.secure_auth= *(my_bool *) arg; - break; - case MYSQL_REPORT_DATA_TRUNCATION: - mysql->options.report_data_truncation= test(*(my_bool *) arg); - break; - case MYSQL_OPT_RECONNECT: - mysql->reconnect= *(my_bool *) arg; - break; - case MYSQL_OPT_SSL_VERIFY_SERVER_CERT: - if (*(my_bool*) arg) - mysql->options.client_flag|= CLIENT_SSL_VERIFY_SERVER_CERT; - else - mysql->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT; - break; - default: - DBUG_RETURN(1); - } - DBUG_RETURN(0); -} - - -/**************************************************************************** - Functions to get information from the MySQL structure - These are functions to make shared libraries more usable. -****************************************************************************/ - -/* MYSQL_RES */ -my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res) -{ - return res->row_count; -} - -unsigned int STDCALL mysql_num_fields(MYSQL_RES *res) -{ - return res->field_count; -} - -uint STDCALL mysql_errno(MYSQL *mysql) -{ - return mysql ? mysql->net.last_errno : mysql_server_last_errno; -} - - -const char * STDCALL mysql_error(MYSQL *mysql) -{ - return mysql ? mysql->net.last_error : mysql_server_last_error; -} - - -/* - Get version number for server in a form easy to test on - - SYNOPSIS - mysql_get_server_version() - mysql Connection - - EXAMPLE - 4.1.0-alfa -> 40100 - - NOTES - We will ensure that a newer server always has a bigger number. - - RETURN - Signed number > 323000 -*/ - -ulong STDCALL -mysql_get_server_version(MYSQL *mysql) -{ - uint major, minor, version; - char *pos= mysql->server_version, *end_pos; - major= (uint) strtoul(pos, &end_pos, 10); pos=end_pos+1; - minor= (uint) strtoul(pos, &end_pos, 10); pos=end_pos+1; - version= (uint) strtoul(pos, &end_pos, 10); - return (ulong) major*10000L+(ulong) (minor*100+version); -} - - -/* - mysql_set_character_set function sends SET NAMES cs_name to - the server (which changes character_set_client, character_set_result - and character_set_connection) and updates mysql->charset so other - functions like mysql_real_escape will work correctly. -*/ -int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name) -{ - struct charset_info_st *cs; - const char *save_csdir= charsets_dir; - - if (mysql->options.charset_dir) - charsets_dir= mysql->options.charset_dir; - - if (strlen(cs_name) < MY_CS_NAME_SIZE && - (cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0)))) - { - char buff[MY_CS_NAME_SIZE + 10]; - charsets_dir= save_csdir; - /* Skip execution of "SET NAMES" for pre-4.1 servers */ - if (mysql_get_server_version(mysql) < 40100) - return 0; - sprintf(buff, "SET NAMES %s", cs_name); - if (!mysql_real_query(mysql, buff, strlen(buff))) - { - mysql->charset= cs; - } - } - else - { - char cs_dir_name[FN_REFLEN]; - get_charsets_dir(cs_dir_name); - set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate, - ER(CR_CANT_READ_CHARSET), cs_name, cs_dir_name); - } - charsets_dir= save_csdir; - return mysql->net.last_errno; -} - - |