Commit 002b1f86 authored by unknown's avatar unknown

resolving of merging conflict


libmysql/libmysql.c:
  conflict resolved
parents 1328c29e 7b2e06b2
...@@ -29,6 +29,7 @@ heikki@rescue. ...@@ -29,6 +29,7 @@ heikki@rescue.
heikki@work.mysql.com heikki@work.mysql.com
hf@bison.(none) hf@bison.(none)
hf@bisonxp.(none) hf@bisonxp.(none)
hf@deer.(none)
hf@deer.mysql.r18.ru hf@deer.mysql.r18.ru
hf@genie.(none) hf@genie.(none)
igor@hundin.mysql.fi igor@hundin.mysql.fi
......
...@@ -169,201 +169,14 @@ void STDCALL mysql_thread_end() ...@@ -169,201 +169,14 @@ void STDCALL mysql_thread_end()
#define reset_sigpipe(mysql) #define reset_sigpipe(mysql)
#endif #endif
#define _libmysql_c
#include "../sql-common/client.c"
static MYSQL* spawn_init(MYSQL* parent, const char* host, static MYSQL* spawn_init(MYSQL* parent, const char* host,
unsigned int port, unsigned int port,
const char* user, const char* user,
const char* passwd); const char* passwd);
/****************************************************************************
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>
*****************************************************************************/
my_bool my_connect(my_socket s, const struct sockaddr *name,
uint namelen, uint timeout)
{
#if defined(__WIN__) || defined(OS2) || defined(__NETWARE__)
return connect(s, (struct sockaddr*) name, namelen) != 0;
#else
int flags, res, s_err;
SOCKOPT_OPTLEN_TYPE s_err_size = sizeof(uint);
fd_set sfds;
struct timeval tv;
time_t start_time, now_time;
/*
If they passed us a timeout of zero, we should behave
exactly like the normal connect() call does.
*/
if (timeout == 0)
return connect(s, (struct sockaddr*) name, namelen) != 0;
flags = fcntl(s, F_GETFL, 0); /* Set socket to not block */
#ifdef O_NONBLOCK
fcntl(s, F_SETFL, flags | O_NONBLOCK); /* and save the flags.. */
#endif
res = connect(s, (struct sockaddr*) name, namelen);
s_err = errno; /* Save the error... */
fcntl(s, F_SETFL, flags);
if ((res != 0) && (s_err != EINPROGRESS))
{
errno = s_err; /* Restore it */
return(1);
}
if (res == 0) /* Connected quickly! */
return(0);
/*
Otherwise, our connection is "in progress." We can use
the select() call to wait up to a specified period of time
for the connection to succeed. If select() returns 0
(after waiting howevermany seconds), our socket never became
writable (host is probably unreachable.) Otherwise, if
select() returns 1, then one of two conditions exist:
1. An error occured. We use getsockopt() to check for this.
2. The connection was set up sucessfully: getsockopt() will
return 0 as an error.
Thanks goes to Andrew Gierth <andrew@erlenstar.demon.co.uk>
who posted this method of timing out a connect() in
comp.unix.programmer on August 15th, 1997.
*/
FD_ZERO(&sfds);
FD_SET(s, &sfds);
/*
select could be interrupted by a signal, and if it is,
the timeout should be adjusted and the select restarted
to work around OSes that don't restart select and
implementations of select that don't adjust tv upon
failure to reflect the time remaining
*/
start_time = time(NULL);
for (;;)
{
tv.tv_sec = (long) timeout;
tv.tv_usec = 0;
#if defined(HPUX10) && defined(THREAD)
if ((res = select(s+1, NULL, (int*) &sfds, NULL, &tv)) > 0)
break;
#else
if ((res = select(s+1, NULL, &sfds, NULL, &tv)) > 0)
break;
#endif
if (res == 0) /* timeout */
return -1;
now_time=time(NULL);
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(s, 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
}
/*
Create a named pipe connection
*/
#ifdef __WIN__
HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
char **arg_unix_socket)
{
HANDLE hPipe=INVALID_HANDLE_VALUE;
char szPipeName [ 257 ];
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;
sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
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(szPipeName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL )) != INVALID_HANDLE_VALUE)
break;
if (GetLastError() != ERROR_PIPE_BUSY)
{
net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
strmov(net->sqlstate, unknown_sqlstate);
sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
(ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
/* wait for for an other instance */
if (! WaitNamedPipe(szPipeName, connect_timeout*1000) )
{
net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
strmov(net->sqlstate, unknown_sqlstate);
sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
(ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
}
if (hPipe == INVALID_HANDLE_VALUE)
{
net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
strmov(net->sqlstate, unknown_sqlstate);
sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
(ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
{
CloseHandle( hPipe );
net->last_errno=CR_NAMEDPIPESETSTATE_ERROR;
strmov(net->sqlstate, unknown_sqlstate);
sprintf(net->last_error,ER(net->last_errno),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 Create new shared memory connection, return handler of connection
...@@ -568,221 +381,6 @@ err: ...@@ -568,221 +381,6 @@ err:
} }
#endif #endif
/*****************************************************************************
Read a packet from server. Give error message if socket was down
or packet is an error message
*****************************************************************************/
ulong
net_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: %d",
vio_description(net->vio),len));
end_server(mysql);
net->last_errno=(net->last_errno == ER_NET_PACKET_TOO_LARGE ?
CR_NET_PACKET_TOO_LARGE:
CR_SERVER_LOST);
strmov(net->last_error,ER(net->last_errno));
strmov(net->sqlstate, 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;
}
(void) strmake(net->last_error,(char*) pos,
min((uint) len,(uint) sizeof(net->last_error)-1));
}
else
{
net->last_errno=CR_UNKNOWN_ERROR;
strmov(net->sqlstate, unknown_sqlstate);
strmov(net->last_error, ER(net->last_errno));
}
DBUG_PRINT("error",("Got error: %d/%s (%s)",
net->last_errno, net->sqlstate, net->last_error));
return(packet_error);
}
return len;
}
static void free_rows(MYSQL_DATA *cur)
{
if (cur)
{
free_root(&cur->alloc,MYF(0));
my_free((gptr) cur,MYF(0));
}
}
static my_bool
advanced_command(MYSQL *mysql, enum enum_server_command command,
const char *header, ulong header_length,
const char *arg, ulong arg_length, my_bool skip_check)
{
NET *net= &mysql->net;
my_bool result= 1;
init_sigpipe_variables
/* 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))
return 1;
}
if (mysql->status != MYSQL_STATUS_READY)
{
strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
strmov(net->sqlstate, unknown_sqlstate);
return 1;
}
net->last_error[0]=0;
net->last_errno=0;
strmov(net->sqlstate, unknown_sqlstate);
mysql->info=0;
mysql->affected_rows= ~(my_ulonglong) 0;
net_clear(&mysql->net); /* Clear receive buffer */
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)
{
net->last_errno=CR_NET_PACKET_TOO_LARGE;
strmov(net->last_error,ER(net->last_errno));
goto end;
}
end_server(mysql);
if (mysql_reconnect(mysql))
goto end;
if (net_write_command(net,(uchar) command, header, header_length,
arg, arg_length))
{
net->last_errno=CR_SERVER_GONE_ERROR;
strmov(net->last_error,ER(net->last_errno));
goto end;
}
}
result=0;
if (!skip_check)
result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ?
1 : 0);
end:
reset_sigpipe(mysql);
return result;
}
my_bool
simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
ulong length, my_bool skip_check)
{
return advanced_command(mysql, command, NullS, 0, arg, length, skip_check);
}
static 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 */
DBUG_VOID_RETURN;
}
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
struct passwd *getpwuid(uid_t);
char* getlogin(void);
#endif
#if defined(__NETWARE__)
/* default to "root" on NetWare */
static void read_user_name(char *name)
{
char *str=getenv("USER");
strmake(name, str ? str : "UNKNOWN_USER", USERNAME_LENGTH);
}
#elif !defined(MSDOS) && ! defined(VMS) && !defined(__WIN__) && !defined(OS2)
static void read_user_name(char *name)
{
DBUG_ENTER("read_user_name");
if (geteuid() == 0)
(void) strmov(name,"root"); /* allow use of surun */
else
{
#ifdef HAVE_GETPWUID
struct passwd *skr;
const char *str;
if ((str=getlogin()) == NULL)
{
if ((skr=getpwuid(geteuid())) != NULL)
str=skr->pw_name;
else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) &&
!(str=getenv("LOGIN")))
str="UNKNOWN_USER";
}
(void) strmake(name,str,USERNAME_LENGTH);
#elif HAVE_CUSERID
(void) cuserid(name);
#else
strmov(name,"UNKNOWN_USER");
#endif
}
DBUG_VOID_RETURN;
}
#else /* If MSDOS || VMS */
static void read_user_name(char *name)
{
char *str=getenv("USER"); /* ODBC will send user variable */
strmake(name,str ? str : "ODBC", USERNAME_LENGTH);
}
#endif
#ifdef __WIN__
static my_bool is_NT(void)
{
char *os=getenv("OS");
return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
}
#endif
/* /*
Expand wildcard to a sql string Expand wildcard to a sql string
*/ */
...@@ -859,1707 +457,349 @@ pipe_sig_handler(int sig __attribute__((unused))) ...@@ -859,1707 +457,349 @@ pipe_sig_handler(int sig __attribute__((unused)))
#endif #endif
} }
/* perform query on master */
my_bool STDCALL mysql_master_query(MYSQL *mysql, const char *q,
unsigned long length)
{
DBUG_ENTER("mysql_master_query");
if (mysql_master_send_query(mysql, q, length))
DBUG_RETURN(1);
DBUG_RETURN(mysql_read_query_result(mysql));
}
/************************************************************************** my_bool STDCALL mysql_master_send_query(MYSQL *mysql, const char *q,
Shut down connection unsigned long length)
**************************************************************************/
static void
end_server(MYSQL *mysql)
{ {
DBUG_ENTER("end_server"); MYSQL *master = mysql->master;
if (mysql->net.vio != 0) DBUG_ENTER("mysql_master_send_query");
{ if (!master->net.vio && !mysql_real_connect(master,0,0,0,0,0,0,0))
init_sigpipe_variables DBUG_RETURN(1);
DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio))); mysql->last_used_con = master;
set_sigpipe(mysql); DBUG_RETURN(simple_command(master, COM_QUERY, q, length, 1));
vio_delete(mysql->net.vio);
reset_sigpipe(mysql);
mysql->net.vio= 0; /* Marker */
}
net_end(&mysql->net);
free_old_query(mysql);
DBUG_VOID_RETURN;
} }
void STDCALL /* perform query on slave */
mysql_free_result(MYSQL_RES *result) my_bool STDCALL mysql_slave_query(MYSQL *mysql, const char *q,
unsigned long length)
{ {
DBUG_ENTER("mysql_free_result"); DBUG_ENTER("mysql_slave_query");
DBUG_PRINT("enter",("mysql_res: %lx",result)); if (mysql_slave_send_query(mysql, q, length))
if (result) DBUG_RETURN(1);
{ DBUG_RETURN(mysql_read_query_result(mysql));
if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
{
DBUG_PRINT("warning",("Not all rows in set where read; Ignoring rows"));
for (;;)
{
ulong pkt_len;
if ((pkt_len=net_safe_read(result->handle)) == packet_error)
break;
if (pkt_len <= 8 && result->handle->net.read_pos[0] == 254)
break; /* End of data */
}
result->handle->status=MYSQL_STATUS_READY;
}
free_rows(result->data);
if (result->fields)
free_root(&result->field_alloc,MYF(0));
if (result->row)
my_free((gptr) result->row,MYF(0));
my_free((gptr) result,MYF(0));
}
DBUG_VOID_RETURN;
} }
/**************************************************************************** my_bool STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q,
Get options from my.cnf unsigned long length)
****************************************************************************/
static const char *default_options[]=
{ {
"port","socket","compress","password","pipe", "timeout", "user", MYSQL* last_used_slave, *slave_to_use = 0;
"init-command", "host", "database", "debug", "return-found-rows", DBUG_ENTER("mysql_slave_send_query");
"ssl-key" ,"ssl-cert" ,"ssl-ca" ,"ssl-capath",
"character-sets-dir", "default-character-set", "interactive-timeout", if ((last_used_slave = mysql->last_used_slave))
"connect-timeout", "local-infile", "disable-local-infile", slave_to_use = last_used_slave->next_slave;
"replication-probe", "enable-reads-from-master", "repl-parse-query", else
"ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name", slave_to_use = mysql->next_slave;
"multi-results", "multi-queries", /*
NullS Next_slave is always safe to use - we have a circular list of slaves
}; if there are no slaves, mysql->next_slave == mysql
*/
mysql->last_used_con = mysql->last_used_slave = slave_to_use;
if (!slave_to_use->net.vio && !mysql_real_connect(slave_to_use, 0,0,0,
0,0,0,0))
DBUG_RETURN(1);
DBUG_RETURN(simple_command(slave_to_use, COM_QUERY, q, length, 1));
}
static TYPELIB option_types={array_elements(default_options)-1,
"options",default_options};
static int add_init_command(struct st_mysql_options *options, const char *cmd) /* enable/disable parsing of all queries to decide
if they go on master or slave */
void STDCALL mysql_enable_rpl_parse(MYSQL* mysql)
{ {
char *tmp; mysql->options.rpl_parse = 1;
}
if (!options->init_commands) void STDCALL mysql_disable_rpl_parse(MYSQL* mysql)
{ {
options->init_commands= (DYNAMIC_ARRAY*)my_malloc(sizeof(DYNAMIC_ARRAY), mysql->options.rpl_parse = 0;
MYF(MY_WME)); }
init_dynamic_array(options->init_commands,sizeof(char*),0,5 CALLER_INFO);
}
if (!(tmp= my_strdup(cmd,MYF(MY_WME))) || /* get the value of the parse flag */
insert_dynamic(options->init_commands, (gptr)&tmp)) int STDCALL mysql_rpl_parse_enabled(MYSQL* mysql)
{ {
my_free(tmp, MYF(MY_ALLOW_ZERO_PTR)); return mysql->options.rpl_parse;
return 1; }
}
return 0; /* enable/disable reads from master */
void STDCALL mysql_enable_reads_from_master(MYSQL* mysql)
{
mysql->options.no_master_reads = 0;
} }
static void mysql_read_default_options(struct st_mysql_options *options, void STDCALL mysql_disable_reads_from_master(MYSQL* mysql)
const char *filename,const char *group)
{ {
int argc; mysql->options.no_master_reads = 1;
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"; /* get the value of the master read flag */
groups[0]= (char*) "client"; groups[1]= (char*) group; groups[2]=0; my_bool STDCALL mysql_reads_from_master_enabled(MYSQL* mysql)
{
load_defaults(filename, groups, &argc, &argv); return !(mysql->options.no_master_reads);
if (argc != 1) /* If some default option */ }
{
char **option=argv;
while (*++option)
{
/* 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 */
mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace");
break;
case 12: /* return-found-rows */
options->client_flag|=CLIENT_FOUND_ROWS;
break;
#ifdef HAVE_OPENSSL
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;
#else
case 13: /* Ignore SSL options */
case 14:
case 15:
case 16:
break;
#endif /* HAVE_OPENSSL */
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 23: /* replication probe */
options->rpl_probe= 1;
break;
case 24: /* enable-reads-from-master */
options->no_master_reads= 0;
break;
case 25: /* repl-parse-query */
options->rpl_parse= 1;
break;
case 27:
options->max_allowed_packet= atoi(opt_arg);
break;
case 28: /* protocol */
if ((options->protocol = find_type(opt_arg, &sql_protocol_typelib,0)) == ~(ulong) 0)
{
fprintf(stderr, "Unknown option to protocol: %s\n", opt_arg);
exit(1);
}
break;
case 29: /* 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 30:
options->client_flag|= CLIENT_MULTI_RESULTS;
break;
case 31:
options->client_flag|= CLIENT_MULTI_QUERIES | CLIENT_MULTI_RESULTS;
break;
default:
DBUG_PRINT("warning",("unknown option: %s",option[0]));
}
}
}
}
free_defaults(argv);
DBUG_VOID_RETURN;
}
/***************************************************************************
Change field rows to field structs
***************************************************************************/
static 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(MYSQL_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;
fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7);
field->catalog = strdup_root(alloc,(char*) row->data[0]);
field->db = strdup_root(alloc,(char*) row->data[1]);
field->table = strdup_root(alloc,(char*) row->data[2]);
field->org_table= strdup_root(alloc,(char*) row->data[3]);
field->name = strdup_root(alloc,(char*) row->data[4]);
field->org_name = strdup_root(alloc,(char*) row->data[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=strdup_root(alloc,(char*) row->data[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++)
{
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 */
static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
uint 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("read_rows");
if ((pkt_len= net_safe_read(mysql)) == packet_error)
DBUG_RETURN(0);
if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
MYF(MY_WME | MY_ZEROFILL))))
{
net->last_errno=CR_OUT_OF_MEMORY;
strmov(net->sqlstate, unknown_sqlstate);
strmov(net->last_error,ER(net->last_errno));
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);
net->last_errno=CR_OUT_OF_MEMORY;
strmov(net->sqlstate, unknown_sqlstate);
strmov(net->last_error,ER(net->last_errno));
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);
net->last_errno=CR_MALFORMED_PACKET;
strmov(net->sqlstate, unknown_sqlstate);
strmov(net->last_error,ER(net->last_errno));
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=net_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);
DBUG_PRINT("info",("warning_count: %ld", mysql->warning_count));
}
DBUG_PRINT("exit",("Got %d rows",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, *end_pos;
uchar *prev_pos;
NET *net= &mysql->net;
if ((pkt_len=net_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);
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))
{
net->last_errno=CR_UNKNOWN_ERROR;
strmov(net->last_error,ER(net->last_errno));
strmov(net->sqlstate, 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;
}
/* perform query on master */
my_bool STDCALL mysql_master_query(MYSQL *mysql, const char *q,
unsigned long length)
{
DBUG_ENTER("mysql_master_query");
if (mysql_master_send_query(mysql, q, length))
DBUG_RETURN(1);
DBUG_RETURN(mysql_read_query_result(mysql));
}
my_bool STDCALL mysql_master_send_query(MYSQL *mysql, const char *q,
unsigned long length)
{
MYSQL *master = mysql->master;
DBUG_ENTER("mysql_master_send_query");
if (!master->net.vio && !mysql_real_connect(master,0,0,0,0,0,0,0))
DBUG_RETURN(1);
mysql->last_used_con = master;
DBUG_RETURN(simple_command(master, COM_QUERY, q, length, 1));
}
/* perform query on slave */
my_bool STDCALL mysql_slave_query(MYSQL *mysql, const char *q,
unsigned long length)
{
DBUG_ENTER("mysql_slave_query");
if (mysql_slave_send_query(mysql, q, length))
DBUG_RETURN(1);
DBUG_RETURN(mysql_read_query_result(mysql));
}
my_bool STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q,
unsigned long length)
{
MYSQL* last_used_slave, *slave_to_use = 0;
DBUG_ENTER("mysql_slave_send_query");
if ((last_used_slave = mysql->last_used_slave))
slave_to_use = last_used_slave->next_slave;
else
slave_to_use = mysql->next_slave;
/*
Next_slave is always safe to use - we have a circular list of slaves
if there are no slaves, mysql->next_slave == mysql
*/
mysql->last_used_con = mysql->last_used_slave = slave_to_use;
if (!slave_to_use->net.vio && !mysql_real_connect(slave_to_use, 0,0,0,
0,0,0,0))
DBUG_RETURN(1);
DBUG_RETURN(simple_command(slave_to_use, COM_QUERY, q, length, 1));
}
/* enable/disable parsing of all queries to decide
if they go on master or slave */
void STDCALL mysql_enable_rpl_parse(MYSQL* mysql)
{
mysql->options.rpl_parse = 1;
}
void STDCALL mysql_disable_rpl_parse(MYSQL* mysql)
{
mysql->options.rpl_parse = 0;
}
/* get the value of the parse flag */
int STDCALL mysql_rpl_parse_enabled(MYSQL* mysql)
{
return mysql->options.rpl_parse;
}
/* enable/disable reads from master */
void STDCALL mysql_enable_reads_from_master(MYSQL* mysql)
{
mysql->options.no_master_reads = 0;
}
void STDCALL mysql_disable_reads_from_master(MYSQL* mysql)
{
mysql->options.no_master_reads = 1;
}
/* get the value of the master read flag */
my_bool STDCALL mysql_reads_from_master_enabled(MYSQL* mysql)
{
return !(mysql->options.no_master_reads);
}
/*
We may get an error while doing replication internals.
In this case, we add a special explanation to the original
error
*/
static void expand_error(MYSQL* mysql, int error)
{
char tmp[MYSQL_ERRMSG_SIZE];
char *p;
uint err_length;
strmake(tmp, mysql->net.last_error, MYSQL_ERRMSG_SIZE-1);
p = strmake(mysql->net.last_error, ER(error), MYSQL_ERRMSG_SIZE-1);
err_length= (uint) (p - mysql->net.last_error);
strmake(p, tmp, MYSQL_ERRMSG_SIZE-1 - err_length);
mysql->net.last_errno = error;
}
/*
This function assumes we have just called SHOW SLAVE STATUS and have
read the given result and row
*/
static my_bool get_master(MYSQL* mysql, MYSQL_RES* res, MYSQL_ROW row)
{
MYSQL* master;
DBUG_ENTER("get_master");
if (mysql_num_fields(res) < 3)
DBUG_RETURN(1); /* safety */
/* use the same username and password as the original connection */
if (!(master = spawn_init(mysql, row[0], atoi(row[2]), 0, 0)))
DBUG_RETURN(1);
mysql->master = master;
DBUG_RETURN(0);
}
/*
Assuming we already know that mysql points to a master connection,
retrieve all the slaves
*/
static my_bool get_slaves_from_master(MYSQL* mysql)
{
MYSQL_RES* res = 0;
MYSQL_ROW row;
my_bool error = 1;
int has_auth_info;
int port_ind;
DBUG_ENTER("get_slaves_from_master");
if (!mysql->net.vio && !mysql_real_connect(mysql,0,0,0,0,0,0,0))
{
expand_error(mysql, CR_PROBE_MASTER_CONNECT);
DBUG_RETURN(1);
}
if (mysql_query(mysql, "SHOW SLAVE HOSTS") ||
!(res = mysql_store_result(mysql)))
{
expand_error(mysql, CR_PROBE_SLAVE_HOSTS);
DBUG_RETURN(1);
}
switch (mysql_num_fields(res)) {
case 5:
has_auth_info = 0;
port_ind=2;
break;
case 7:
has_auth_info = 1;
port_ind=4;
break;
default:
goto err;
}
while ((row = mysql_fetch_row(res)))
{
MYSQL* slave;
const char* tmp_user, *tmp_pass;
if (has_auth_info)
{
tmp_user = row[2];
tmp_pass = row[3];
}
else
{
tmp_user = mysql->user;
tmp_pass = mysql->passwd;
}
if (!(slave = spawn_init(mysql, row[1], atoi(row[port_ind]),
tmp_user, tmp_pass)))
goto err;
/* Now add slave into the circular linked list */
slave->next_slave = mysql->next_slave;
mysql->next_slave = slave;
}
error = 0;
err:
if (res)
mysql_free_result(res);
DBUG_RETURN(error);
}
my_bool STDCALL mysql_rpl_probe(MYSQL* mysql)
{
MYSQL_RES *res= 0;
MYSQL_ROW row;
my_bool error= 1;
DBUG_ENTER("mysql_rpl_probe");
/*
First determine the replication role of the server we connected to
the most reliable way to do this is to run SHOW SLAVE STATUS and see
if we have a non-empty master host. This is still not fool-proof -
it is not a sin to have a master that has a dormant slave thread with
a non-empty master host. However, it is more reliable to check
for empty master than whether the slave thread is actually running
*/
if (mysql_query(mysql, "SHOW SLAVE STATUS") ||
!(res = mysql_store_result(mysql)))
{
expand_error(mysql, CR_PROBE_SLAVE_STATUS);
DBUG_RETURN(1);
}
row= mysql_fetch_row(res);
/*
Check master host for emptiness/NULL
For MySQL 4.0 it's enough to check for row[0]
*/
if (row && row[0] && *(row[0]))
{
/* this is a slave, ask it for the master */
if (get_master(mysql, res, row) || get_slaves_from_master(mysql))
goto err;
}
else
{
mysql->master = mysql;
if (get_slaves_from_master(mysql))
goto err;
}
error = 0;
err:
if (res)
mysql_free_result(res);
DBUG_RETURN(error);
}
/*
Make a not so fool-proof decision on where the query should go, to
the master or the slave. Ideally the user should always make this
decision himself with mysql_master_query() or mysql_slave_query().
However, to be able to more easily port the old code, we support the
option of an educated guess - this should work for most applications,
however, it may make the wrong decision in some particular cases. If
that happens, the user would have to change the code to call
mysql_master_query() or mysql_slave_query() explicitly in the place
where we have made the wrong decision
*/
enum mysql_rpl_type
STDCALL mysql_rpl_query_type(const char* q, int len)
{
const char *q_end= q + len;
for (; q < q_end; ++q)
{
char c;
if (my_isalpha(&my_charset_latin1, (c= *q)))
{
switch (my_tolower(&my_charset_latin1,c)) {
case 'i': /* insert */
case 'u': /* update or unlock tables */
case 'l': /* lock tables or load data infile */
case 'd': /* drop or delete */
case 'a': /* alter */
return MYSQL_RPL_MASTER;
case 'c': /* create or check */
return my_tolower(&my_charset_latin1,q[1]) == 'h' ? MYSQL_RPL_ADMIN :
MYSQL_RPL_MASTER;
case 's': /* select or show */
return my_tolower(&my_charset_latin1,q[1]) == 'h' ? MYSQL_RPL_ADMIN :
MYSQL_RPL_SLAVE;
case 'f': /* flush */
case 'r': /* repair */
case 'g': /* grant */
return MYSQL_RPL_ADMIN;
default:
return MYSQL_RPL_SLAVE;
}
}
}
return MYSQL_RPL_MASTER; /* By default, send to master */
}
/****************************************************************************
Init MySQL structure or allocate one
****************************************************************************/
MYSQL * STDCALL
mysql_init(MYSQL *mysql)
{
mysql_once_init();
if (!mysql)
{
if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
return 0;
mysql->free_me=1;
}
else
bzero((char*) (mysql),sizeof(*(mysql)));
mysql->options.connect_timeout=CONNECT_TIMEOUT;
mysql->last_used_con = mysql->next_slave = mysql->master = mysql;
/*
By default, we are a replication pivot. The caller must reset it
after we return if this is not the case.
*/
mysql->rpl_pivot = 1;
#if defined(SIGPIPE) && defined(THREAD) && !defined(__WIN__)
if (!((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE))
(void) signal(SIGPIPE,pipe_sig_handler);
#endif
/*
Only enable LOAD DATA INFILE by default if configured with
--enable-local-infile
*/
#ifdef ENABLED_LOCAL_INFILE
mysql->options.client_flag|= CLIENT_LOCAL_FILES;
#endif
#ifdef HAVE_SMEM
mysql->options.shared_memory_base_name=(char*)def_shared_memory_base_name;
#endif
return mysql;
}
/*
Initialize the MySQL library
SYNOPSIS
mysql_once_init()
NOTES
Can't be static on NetWare
This function is called by mysql_init() and indirectly called
by mysql_query(), so one should never have to call this from an
outside program.
*/
void mysql_once_init(void)
{
if (!mysql_client_init)
{
mysql_client_init=1;
org_my_init_done=my_init_done;
my_init(); /* Will init threads */
init_client_errs();
if (!mysql_port)
{
mysql_port = MYSQL_PORT;
#ifndef MSDOS
{
struct servent *serv_ptr;
char *env;
if ((serv_ptr = getservbyname("mysql", "tcp")))
mysql_port = (uint) ntohs((ushort) serv_ptr->s_port);
if ((env = getenv("MYSQL_TCP_PORT")))
mysql_port =(uint) atoi(env);
}
#endif
}
if (!mysql_unix_port)
{
char *env;
#ifdef __WIN__
mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
#else
mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
#endif
if ((env = getenv("MYSQL_UNIX_PORT")))
mysql_unix_port = env;
}
mysql_debug(NullS);
#if defined(SIGPIPE) && !defined(THREAD) && !defined(__WIN__)
(void) signal(SIGPIPE,SIG_IGN);
#endif
}
#ifdef THREAD
else
my_thread_init(); /* Init if new thread */
#endif
}
/* /*
Fill in SSL part of MYSQL structure and set 'use_ssl' flag. We may get an error while doing replication internals.
NB! Errors are not reported until you do mysql_real_connect. In this case, we add a special explanation to the original
error
*/ */
#define strdup_if_not_null(A) (A) == 0 ? 0 : my_strdup((A),MYF(MY_WME)) static void expand_error(MYSQL* mysql, int error)
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)))
{ {
#ifdef HAVE_OPENSSL char tmp[MYSQL_ERRMSG_SIZE];
mysql->options.ssl_key= strdup_if_not_null(key); char *p;
mysql->options.ssl_cert= strdup_if_not_null(cert); uint err_length;
mysql->options.ssl_ca= strdup_if_not_null(ca); strmake(tmp, mysql->net.last_error, MYSQL_ERRMSG_SIZE-1);
mysql->options.ssl_capath= strdup_if_not_null(capath); p = strmake(mysql->net.last_error, ER(error), MYSQL_ERRMSG_SIZE-1);
mysql->options.ssl_cipher= strdup_if_not_null(cipher); err_length= (uint) (p - mysql->net.last_error);
#endif /* HAVE_OPENSSL */ strmake(p, tmp, MYSQL_ERRMSG_SIZE-1 - err_length);
return 0; mysql->net.last_errno = error;
}
/*
Free strings in the SSL structure and clear 'use_ssl' flag.
NB! Errors are not reported until you do mysql_real_connect.
*/
#ifdef HAVE_OPENSSL
static void
mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
{
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));
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;
} }
#endif /* HAVE_OPENSSL */
/* /*
Handle password authentication This function assumes we have just called SHOW SLAVE STATUS and have
read the given result and row
*/ */
static my_bool mysql_autenticate(MYSQL *mysql, const char *passwd) static my_bool get_master(MYSQL* mysql, MYSQL_RES* res, MYSQL_ROW row)
{ {
ulong pkt_length; MYSQL* master;
NET *net= &mysql->net; DBUG_ENTER("get_master");
char buff[SCRAMBLE41_LENGTH]; if (mysql_num_fields(res) < 3)
char password_hash[SCRAMBLE41_LENGTH]; /* Used for storage of stage1 hash */ DBUG_RETURN(1); /* safety */
/* We shall only query server if it expect us to do so */
if ((pkt_length=net_safe_read(mysql)) == packet_error)
goto error;
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
/*
This should always happen with new server unless empty password
OK/Error packets have zero as the first char
*/
if (pkt_length == 24 && net->read_pos[0])
{
/* Old passwords will have '*' at the first byte of hash */
if (net->read_pos[0] != '*')
{
/* Build full password hash as it is required to decode scramble */
password_hash_stage1(buff, passwd);
/* Store copy as we'll need it later */
memcpy(password_hash,buff,SCRAMBLE41_LENGTH);
/* Finally hash complete password using hash we got from server */
password_hash_stage2(password_hash,(const char*) net->read_pos);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((const char*) net->read_pos+4,mysql->scramble_buff,
password_hash, SCRAMBLE41_LENGTH);
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
/* Encode scramble with password. Recycle buffer */
password_crypt(mysql->scramble_buff,buff,buff,SCRAMBLE41_LENGTH);
}
else
{
/* Create password to decode scramble */
create_key_from_old_password(passwd,password_hash);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((const char*) net->read_pos+4,mysql->scramble_buff,
password_hash, SCRAMBLE41_LENGTH);
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
/* Finally scramble decoded scramble with password */
scramble(buff, mysql->scramble_buff, passwd,0);
}
/* Write second package of authentication */
if (my_net_write(net,buff,SCRAMBLE41_LENGTH) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->sqlstate, unknown_sqlstate);
strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Read what server thinks about out new auth message report */
if (net_safe_read(mysql) == packet_error)
goto error;
}
}
return 0;
error:
return 1;
}
/**************************************************************************
Connect to sql server
If host == 0 then use localhost
**************************************************************************/
#ifdef USE_OLD_FUNCTIONS /* use the same username and password as the original connection */
MYSQL * STDCALL if (!(master = spawn_init(mysql, row[0], atoi(row[2]), 0, 0)))
mysql_connect(MYSQL *mysql,const char *host, DBUG_RETURN(1);
const char *user, const char *passwd) mysql->master = master;
{ DBUG_RETURN(0);
MYSQL *res;
mysql=mysql_init(mysql); /* Make it thread safe */
{
DBUG_ENTER("mysql_connect");
if (!(res=mysql_real_connect(mysql,host,user,passwd,NullS,0,NullS,0)))
{
if (mysql->free_me)
my_free((gptr) mysql,MYF(0));
}
DBUG_RETURN(res);
}
} }
#endif
/*
Note that the mysql argument must be initialized with mysql_init()
before calling mysql_real_connect !
*/
MYSQL * STDCALL
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],charset_name_buff[16];
char *end,*host_info,*charset_name;
my_socket sock;
uint32 ip_addr;
struct sockaddr_in sock_addr;
ulong pkt_length;
NET *net= &mysql->net;
#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)"));
/* Don't give sigpipe errors if the client doesn't want them */
set_sigpipe(mysql);
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 (!passwd)
{
passwd=mysql->options.password;
#ifndef DONT_USE_MYSQL_PWD
if (!passwd)
passwd=getenv("MYSQL_PWD"); /* get it from environment */
#endif
}
if (!db || !db[0])
db=mysql->options.db;
if (!port)
port=mysql->options.port;
if (!unix_socket)
unix_socket=mysql->options.unix_socket;
mysql->reconnect=1; /* Reconnect as default */
mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
/*
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 */
}
else
{
mysql->options.protocol=MYSQL_PROTOCOL_MEMORY;
sock=0;
unix_socket = 0;
host=mysql->options.shared_memory_base_name;
host_info=(char*) ER(CR_SHARED_MEMORY_CONNECTION);
}
} else
#endif /* HAVE_SMEM */
#if defined(HAVE_SYS_UN_H)
if ((!mysql->options.protocol ||
mysql->options.protocol == MYSQL_PROTOCOL_SOCKET)&&
(!host || !strcmp(host,LOCAL_HOST)) &&
(unix_socket || mysql_unix_port))
{
host=LOCAL_HOST;
if (!unix_socket)
unix_socket=mysql_unix_port;
host_info=(char*) ER(CR_LOCALHOST_CONNECTION);
DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
{
net->last_errno=CR_SOCKET_CREATE_ERROR;
strmov(net->sqlstate, unknown_sqlstate);
sprintf(net->last_error,ER(net->last_errno),socket_errno);
goto error;
}
net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
UNIXaddr.sun_family = AF_UNIX;
strmov(UNIXaddr.sun_path, unix_socket);
if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
mysql->options.connect_timeout))
{
DBUG_PRINT("error",("Got error %d on connect to local server",
socket_errno));
net->last_errno=CR_CONNECTION_ERROR;
strmov(net->sqlstate, unknown_sqlstate);
sprintf(net->last_error,ER(net->last_errno),unix_socket,socket_errno);
goto error;
}
else
mysql->options.protocol=MYSQL_PROTOCOL_SOCKET;
}
else
#elif defined(__WIN__)
{
if ((!mysql->options.protocol ||
mysql->options.protocol == MYSQL_PROTOCOL_PIPE)&&
((unix_socket || !host && is_NT() ||
host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||! have_tcpip))&&
(!net->vio))
{
sock=0;
if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
(char**) &host, (char**) &unix_socket)) ==
INVALID_HANDLE_VALUE)
{
DBUG_PRINT("error",
("host: '%s' socket: '%s' have_tcpip: %d",
host ? host : "<null>",
unix_socket ? unix_socket : "<null>",
(int) have_tcpip));
if (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
(host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
(unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
goto error;
/* Try also with TCP/IP */
}
else
{
net->vio=vio_new_win32pipe(hPipe);
sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host,
unix_socket);
}
}
}
#endif
if ((!mysql->options.protocol ||
mysql->options.protocol == MYSQL_PROTOCOL_TCP)&&(!net->vio))
{
unix_socket=0; /* This is not used */
if (!port)
port=mysql_port;
if (!host)
host=LOCAL_HOST;
sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
/* _WIN64 ; Assume that the (int) range is enough for socket() */
if ((sock = (my_socket) socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
{
net->last_errno=CR_IPSOCK_ERROR;
strmov(net->sqlstate, unknown_sqlstate);
sprintf(net->last_error,ER(net->last_errno),socket_errno);
goto error;
}
net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
bzero((char*) &sock_addr,sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
/* /*
The server name may be a host name or IP address Assuming we already know that mysql points to a master connection,
*/ retrieve all the slaves
*/
if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE) static my_bool get_slaves_from_master(MYSQL* mysql)
{ {
memcpy_fixed(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr)); MYSQL_RES* res = 0;
} MYSQL_ROW row;
else my_bool error = 1;
{ int has_auth_info;
int tmp_errno; int port_ind;
struct hostent tmp_hostent,*hp; DBUG_ENTER("get_slaves_from_master");
char buff2[GETHOSTBYNAME_BUFF_SIZE];
hp = my_gethostbyname_r(host,&tmp_hostent,buff2,sizeof(buff2),
&tmp_errno);
if (!hp)
{
my_gethostbyname_r_free();
net->last_errno=CR_UNKNOWN_HOST;
strmov(net->sqlstate, unknown_sqlstate);
sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, tmp_errno);
goto error;
}
memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
my_gethostbyname_r_free();
}
sock_addr.sin_port = (ushort) htons((ushort) port);
if (my_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
mysql->options.connect_timeout))
{
DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,
host));
net->last_errno= CR_CONN_HOST_ERROR;
strmov(net->sqlstate, unknown_sqlstate);
sprintf(net->last_error ,ER(CR_CONN_HOST_ERROR), host, socket_errno);
goto error;
}
}
else if (!net->vio)
{
DBUG_PRINT("error",("Unknow protocol %d ",mysql->options.protocol));
net->last_errno= CR_CONN_UNKNOW_PROTOCOL;
strmov(net->sqlstate, unknown_sqlstate);
sprintf(net->last_error ,ER(CR_CONN_UNKNOW_PROTOCOL));
goto error;
}
if (!net->vio || my_net_init(net, net->vio)) if (!mysql->net.vio && !mysql_real_connect(mysql,0,0,0,0,0,0,0))
{ {
vio_delete(net->vio); expand_error(mysql, CR_PROBE_MASTER_CONNECT);
net->vio = 0; DBUG_RETURN(1);
net->last_errno=CR_OUT_OF_MEMORY;
strmov(net->sqlstate, unknown_sqlstate);
strmov(net->last_error,ER(net->last_errno));
goto error;
} }
vio_keepalive(net->vio,TRUE);
/* Get version info */ if (mysql_query(mysql, "SHOW SLAVE HOSTS") ||
mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */ !(res = mysql_store_result(mysql)))
if (mysql->options.connect_timeout &&
vio_poll_read(net->vio, mysql->options.connect_timeout))
{ {
net->last_errno= CR_SERVER_LOST; expand_error(mysql, CR_PROBE_SLAVE_HOSTS);
strmov(net->sqlstate, unknown_sqlstate); DBUG_RETURN(1);
strmov(net->last_error,ER(net->last_errno));
goto error;
} }
if ((pkt_length=net_safe_read(mysql)) == packet_error)
goto error;
/* Check if version of protocol matches current one */ switch (mysql_num_fields(res)) {
case 5:
mysql->protocol_version= net->read_pos[0]; has_auth_info = 0;
DBUG_DUMP("packet",(char*) net->read_pos,10); port_ind=2;
DBUG_PRINT("info",("mysql protocol version %d, server=%d", break;
PROTOCOL_VERSION, mysql->protocol_version)); case 7:
if (mysql->protocol_version != PROTOCOL_VERSION) has_auth_info = 1;
{ port_ind=4;
net->last_errno= CR_VERSION_ERROR; break;
strmov(net->sqlstate, unknown_sqlstate); default:
sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version, goto err;
PROTOCOL_VERSION);
goto error;
}
end=strend((char*) net->read_pos+1);
mysql->thread_id=uint4korr(end+1);
end+=5;
strmake(mysql->scramble_buff,end,8);
end+=9;
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);
} }
/* Set character set */ while ((row = mysql_fetch_row(res)))
if ((charset_name=mysql->options.charset_name))
{
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));
charsets_dir=save;
}
else if (mysql->server_language)
{ {
charset_name=charset_name_buff; MYSQL* slave;
sprintf(charset_name,"%d",mysql->server_language); /* In case of errors */ const char* tmp_user, *tmp_pass;
if (!(mysql->charset =
get_charset((uint8) mysql->server_language, MYF(0))))
mysql->charset = default_charset_info; /* shouldn't be fatal */
}
else
mysql->charset=default_charset_info;
if (!mysql->charset) if (has_auth_info)
{ {
net->last_errno=CR_CANT_READ_CHARSET; tmp_user = row[2];
strmov(net->sqlstate, unknown_sqlstate); tmp_pass = row[3];
if (mysql->options.charset_dir) }
sprintf(net->last_error,ER(net->last_errno),
charset_name ? charset_name : "unknown",
mysql->options.charset_dir);
else else
{ {
char cs_dir_name[FN_REFLEN]; tmp_user = mysql->user;
get_charsets_dir(cs_dir_name); tmp_pass = mysql->passwd;
sprintf(net->last_error,ER(net->last_errno),
charset_name ? charset_name : "unknown",
cs_dir_name);
}
goto error;
} }
/* Save connection information */ if (!(slave = spawn_init(mysql, row[1], atoi(row[port_ind]),
if (!user) user=""; tmp_user, tmp_pass)))
if (!passwd) passwd=""; goto err;
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))))
{
strmov(net->sqlstate, unknown_sqlstate);
strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY));
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;
client_flag|=mysql->options.client_flag;
/* Send client information for access check */ /* Now add slave into the circular linked list */
client_flag|=CLIENT_CAPABILITIES; slave->next_slave = mysql->next_slave;
if (client_flag & CLIENT_MULTI_QUERIES) mysql->next_slave = slave;
client_flag|= CLIENT_MULTI_RESULTS; }
error = 0;
err:
if (res)
mysql_free_result(res);
DBUG_RETURN(error);
}
#ifdef HAVE_OPENSSL
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 */
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) my_bool STDCALL mysql_rpl_probe(MYSQL* mysql)
{ {
/* 4.1 server and 4.1 client has a 32 byte option flag */ MYSQL_RES *res= 0;
int4store(buff,client_flag); MYSQL_ROW row;
int4store(buff+4,max_allowed_packet); my_bool error= 1;
buff[8]= mysql->charset->number; DBUG_ENTER("mysql_rpl_probe");
bzero(buff+9, 32-9);
end= buff+32;
}
else
{
int2store(buff,client_flag);
int3store(buff+2,max_allowed_packet);
end= buff+5;
}
mysql->client_flag=client_flag;
#ifdef HAVE_OPENSSL
/* /*
Oops.. are we careful enough to not send ANY information without First determine the replication role of the server we connected to
encryption? the most reliable way to do this is to run SHOW SLAVE STATUS and see
if we have a non-empty master host. This is still not fool-proof -
it is not a sin to have a master that has a dormant slave thread with
a non-empty master host. However, it is more reliable to check
for empty master than whether the slave thread is actually running
*/ */
if (client_flag & CLIENT_SSL) if (mysql_query(mysql, "SHOW SLAVE STATUS") ||
{ !(res = mysql_store_result(mysql)))
struct st_mysql_options *options= &mysql->options;
if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net))
{
strmov(net->sqlstate, unknown_sqlstate);
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Do the SSL layering. */
if (!(mysql->connector_fd=
(gptr) new_VioSSLConnectorFd(options->ssl_key,
options->ssl_cert,
options->ssl_ca,
options->ssl_capath,
options->ssl_cipher)))
{
strmov(net->sqlstate, unknown_sqlstate);
net->last_errno= CR_SSL_CONNECTION_ERROR;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
DBUG_PRINT("info", ("IO layer change in progress..."));
if (sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd),
mysql->net.vio, (long) (mysql->options.connect_timeout)))
{ {
strmov(net->sqlstate, unknown_sqlstate); expand_error(mysql, CR_PROBE_SLAVE_STATUS);
net->last_errno= CR_SSL_CONNECTION_ERROR; DBUG_RETURN(1);
strmov(net->last_error,ER(net->last_errno));
goto error;
}
DBUG_PRINT("info", ("IO layer change done!"));
} }
#endif /* HAVE_OPENSSL */
DBUG_PRINT("info",("Server version = '%s' capabilites: %lu status: %u client_flag: %lu", row= mysql_fetch_row(res);
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,32); /* 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));
/* /*
We always start with old type handshake the only difference is message sent Check master host for emptiness/NULL
If server handles secure connection type we'll not send the real scramble For MySQL 4.0 it's enough to check for row[0]
*/ */
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) if (row && row[0] && *(row[0]))
{
if (passwd[0])
{
/* Prepare false scramble */
end=strend(end)+1;
bfill(end, SCRAMBLE_LENGTH, 'x');
end+=SCRAMBLE_LENGTH;
*end=0;
}
else /* For empty password*/
{ {
end=strend(end)+1; /* this is a slave, ask it for the master */
*end=0; /* Store zero length scramble */ if (get_master(mysql, res, row) || get_slaves_from_master(mysql))
} goto err;
} }
else else
{ {
/* mysql->master = mysql;
Real scramble is only sent to old servers. This can be blocked if (get_slaves_from_master(mysql))
by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1); goto err;
*/
end=scramble(strend(end)+1, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
}
/* Add database if needed */
if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
{
end=strmake(end+1,db,NAME_LEN);
mysql->db=my_strdup(db,MYF(MY_WME));
db=0;
}
/* Write authentication package */
if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net))
{
strmov(net->sqlstate, unknown_sqlstate);
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
} }
if (mysql_autenticate(mysql, passwd)) error = 0;
goto error; err:
if (res)
if (client_flag & CLIENT_COMPRESS) /* We will use compression */ mysql_free_result(res);
net->compress=1; DBUG_RETURN(error);
if (mysql->options.max_allowed_packet) }
net->max_packet_size= mysql->options.max_allowed_packet;
if (db && mysql_select_db(mysql,db))
goto error;
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;
my_bool reconnect=mysql->reconnect; /*
mysql->reconnect=0; Make a not so fool-proof decision on where the query should go, to
the master or the slave. Ideally the user should always make this
decision himself with mysql_master_query() or mysql_slave_query().
However, to be able to more easily port the old code, we support the
option of an educated guess - this should work for most applications,
however, it may make the wrong decision in some particular cases. If
that happens, the user would have to change the code to call
mysql_master_query() or mysql_slave_query() explicitly in the place
where we have made the wrong decision
*/
for (; ptr<end; ptr++) enum mysql_rpl_type
STDCALL mysql_rpl_query_type(const char* q, int len)
{
const char *q_end= q + len;
for (; q < q_end; ++q)
{ {
MYSQL_RES *res; char c;
if (mysql_query(mysql,*ptr)) if (my_isalpha(&my_charset_latin1, (c= *q)))
goto error;
if (mysql->fields)
{ {
if (!(res= mysql_use_result(mysql))) switch (my_tolower(&my_charset_latin1,c)) {
goto error; case 'i': /* insert */
mysql_free_result(res); case 'u': /* update or unlock tables */
} case 'l': /* lock tables or load data infile */
case 'd': /* drop or delete */
case 'a': /* alter */
return MYSQL_RPL_MASTER;
case 'c': /* create or check */
return my_tolower(&my_charset_latin1,q[1]) == 'h' ? MYSQL_RPL_ADMIN :
MYSQL_RPL_MASTER;
case 's': /* select or show */
return my_tolower(&my_charset_latin1,q[1]) == 'h' ? MYSQL_RPL_ADMIN :
MYSQL_RPL_SLAVE;
case 'f': /* flush */
case 'r': /* repair */
case 'g': /* grant */
return MYSQL_RPL_ADMIN;
default:
return MYSQL_RPL_SLAVE;
} }
mysql->reconnect=reconnect;
} }
if (mysql->options.rpl_probe && mysql_rpl_probe(mysql))
goto error;
DBUG_PRINT("exit",("Mysql handler: %lx",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 */
my_bool free_me=mysql->free_me;
end_server(mysql);
mysql->free_me=0;
mysql_close(mysql);
mysql->free_me=free_me;
} }
DBUG_RETURN(0); return MYSQL_RPL_MASTER; /* By default, send to master */
} }
/*
Fill in SSL part of MYSQL structure and set 'use_ssl' flag.
NB! Errors are not reported until you do mysql_real_connect.
*/
/* needed when we move MYSQL structure to a different address */ #define strdup_if_not_null(A) (A) == 0 ? 0 : my_strdup((A),MYF(MY_WME))
static void mysql_fix_pointers(MYSQL* mysql, MYSQL* old_mysql) 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)))
{ {
MYSQL *tmp, *tmp_prev; #ifdef HAVE_OPENSSL
if (mysql->master == old_mysql) mysql->options.ssl_key= strdup_if_not_null(key);
mysql->master = mysql; mysql->options.ssl_cert= strdup_if_not_null(cert);
if (mysql->last_used_con == old_mysql) mysql->options.ssl_ca= strdup_if_not_null(ca);
mysql->last_used_con = mysql; mysql->options.ssl_capath= strdup_if_not_null(capath);
if (mysql->last_used_slave == old_mysql) mysql->options.ssl_cipher= strdup_if_not_null(cipher);
mysql->last_used_slave = mysql; #endif /* HAVE_OPENSSL */
for (tmp_prev = mysql, tmp = mysql->next_slave; return 0;
tmp != old_mysql;tmp = tmp->next_slave)
{
tmp_prev = tmp;
}
tmp_prev->next_slave = mysql;
} }
/**************************************************************************
Connect to sql server
If host == 0 then use localhost
**************************************************************************/
static my_bool mysql_reconnect(MYSQL *mysql) #ifdef USE_OLD_FUNCTIONS
MYSQL * STDCALL
mysql_connect(MYSQL *mysql,const char *host,
const char *user, const char *passwd)
{ {
MYSQL tmp_mysql; MYSQL *res;
DBUG_ENTER("mysql_reconnect"); mysql=mysql_init(mysql); /* Make it thread safe */
if (!mysql->reconnect ||
(mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
{ {
/* Allow reconnect next time */ DBUG_ENTER("mysql_connect");
mysql->server_status&= ~SERVER_STATUS_IN_TRANS; if (!(res=mysql_real_connect(mysql,host,user,passwd,NullS,0,NullS,0)))
strmov(mysql->net.sqlstate, unknown_sqlstate); {
mysql->net.last_errno=CR_SERVER_GONE_ERROR; if (mysql->free_me)
strmov(mysql->net.last_error,ER(mysql->net.last_errno)); my_free((gptr) mysql,MYF(0));
DBUG_RETURN(1);
} }
mysql_init(&tmp_mysql); DBUG_RETURN(res);
tmp_mysql.options=mysql->options;
bzero((char*) &mysql->options,sizeof(mysql->options));
tmp_mysql.rpl_pivot = mysql->rpl_pivot;
if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
mysql->db, mysql->port, mysql->unix_socket,
mysql->client_flag))
{
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);
} }
tmp_mysql.free_me=mysql->free_me;
mysql->free_me=0;
mysql_close(mysql);
*mysql=tmp_mysql;
mysql_fix_pointers(mysql, &tmp_mysql); /* adjust connection pointers */
net_clear(&mysql->net);
mysql->affected_rows= ~(my_ulonglong) 0;
DBUG_RETURN(0);
} }
#endif
/************************************************************************** /**************************************************************************
Change user and database Change user and database
...@@ -2629,111 +869,6 @@ error: ...@@ -2629,111 +869,6 @@ error:
DBUG_RETURN(1); DBUG_RETURN(1);
} }
/**************************************************************************
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,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.
*************************************************************************/
void STDCALL
mysql_close(MYSQL *mysql)
{
DBUG_ENTER("mysql_close");
if (mysql) /* Some simple safety */
{
if (mysql->net.vio != 0)
{
free_old_query(mysql);
mysql->status=MYSQL_STATUS_READY; /* Force command */
mysql->reconnect=0;
simple_command(mysql,COM_QUIT,NullS,0,1);
end_server(mysql); /* Sets mysql->net.vio= 0 */
}
my_free((gptr) 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));
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));
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));
}
#ifdef HAVE_OPENSSL
mysql_ssl_free(mysql);
#endif /* HAVE_OPENSSL */
#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 */
/* Clear pointers for better safety */
mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
bzero((char*) &mysql->options,sizeof(mysql->options));
/* free/close slave list */
if (mysql->rpl_pivot)
{
MYSQL* tmp;
for (tmp = mysql->next_slave; tmp != mysql; )
{
/* trick to avoid following freed pointer */
MYSQL* tmp1 = tmp->next_slave;
mysql_close(tmp);
tmp = tmp1;
}
mysql->rpl_pivot=0;
}
if (mysql->stmts)
{
/* Free any open prepared statements */
LIST *element, *next_element;
for (element= mysql->stmts; element; element= next_element)
{
next_element= element->next;
stmt_close((MYSQL_STMT *)element->data, 0);
}
}
if (mysql != mysql->master)
mysql_close(mysql->master);
if (mysql->free_me)
my_free((gptr) mysql,MYF(0));
}
DBUG_VOID_RETURN;
}
/************************************************************************** /**************************************************************************
Do a query. If query returned rows, free old rows. Do a query. If query returned rows, free old rows.
Read data by mysql_store_result or by repeat call of mysql_fetch_row Read data by mysql_store_result or by repeat call of mysql_fetch_row
...@@ -2806,233 +941,6 @@ STDCALL mysql_add_slave(MYSQL* mysql, const char* host, ...@@ -2806,233 +941,6 @@ STDCALL mysql_add_slave(MYSQL* mysql, const char* host,
return 0; 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_PRINT("enter",("rpl_parse: %d rpl_pivot: %d",
mysql->options.rpl_parse, mysql->rpl_pivot));
if (mysql->options.rpl_parse && mysql->rpl_pivot)
{
switch (mysql_rpl_query_type(query, length)) {
case MYSQL_RPL_MASTER:
DBUG_RETURN(mysql_master_send_query(mysql, query, length));
case MYSQL_RPL_SLAVE:
DBUG_RETURN(mysql_slave_send_query(mysql, query, length));
case MYSQL_RPL_ADMIN:
break; /* fall through */
}
}
mysql->last_used_con = mysql;
DBUG_RETURN(simple_command(mysql, COM_QUERY, query, length, 1));
}
my_bool STDCALL mysql_read_query_result(MYSQL *mysql)
{
uchar *pos;
ulong field_count;
MYSQL_DATA *fields;
ulong length;
DBUG_ENTER("mysql_read_query_result");
/*
Read from the connection which we actually used, which
could differ from the original connection if we have slaves
*/
mysql = mysql->last_used_con;
if ((length = net_safe_read(mysql)) == packet_error)
DBUG_RETURN(1);
free_old_query(mysql); /* Free old result */
get_info:
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);
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->server_status=uint2korr(pos); pos+=2;
mysql->warning_count= 0;
}
DBUG_PRINT("info",("status: %ld warning_count: %ld",
mysql->server_status, mysql->warning_count));
if (pos < mysql->net.read_pos+length && net_field_length(&pos))
mysql->info=(char*) pos;
DBUG_RETURN(0);
}
if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
{
int error=send_file_to_server(mysql,(char*) pos);
if ((length=net_safe_read(mysql)) == packet_error || error)
DBUG_RETURN(1);
goto get_info; /* Get info packet */
}
if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
mysql->server_status|= SERVER_STATUS_IN_TRANS;
mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
if (!(fields=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;
mysql->warning_count= 0;
DBUG_RETURN(0);
}
int STDCALL
mysql_real_query(MYSQL *mysql, const char *query, ulong length)
{
DBUG_ENTER("mysql_real_query");
DBUG_PRINT("enter",("handle: %lx",mysql));
DBUG_PRINT("query",("Query = '%-.4096s'",query));
if (mysql_send_query(mysql,query,length))
DBUG_RETURN(1);
DBUG_RETURN((int) mysql_read_query_result(mysql));
}
static my_bool
send_file_to_server(MYSQL *mysql, const char *filename)
{
int fd, readcount;
my_bool result= 1;
uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE);
char *buf, tmp_name[FN_REFLEN];
NET *net= &mysql->net;
DBUG_ENTER("send_file_to_server");
if (!(buf=my_malloc(packet_length,MYF(0))))
{
strmov(net->sqlstate, unknown_sqlstate);
strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY));
DBUG_RETURN(1);
}
fn_format(tmp_name,filename,"","",4); /* Convert to client format */
if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0)
{
my_net_write(net,"",0); /* Server needs one packet */
net_flush(net);
strmov(net->sqlstate, unknown_sqlstate);
net->last_errno=EE_FILENOTFOUND;
my_snprintf(net->last_error,sizeof(net->last_error)-1,
EE(net->last_errno),tmp_name, errno);
goto err;
}
while ((readcount = (int) my_read(fd,(byte*) buf,packet_length,MYF(0))) > 0)
{
if (my_net_write(net,buf,readcount))
{
DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file"));
strmov(net->sqlstate, unknown_sqlstate);
net->last_errno=CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto err;
}
}
/* Send empty packet to mark end of file */
if (my_net_write(net,"",0) || net_flush(net))
{
strmov(net->sqlstate, unknown_sqlstate);
net->last_errno=CR_SERVER_LOST;
sprintf(net->last_error,ER(net->last_errno),errno);
goto err;
}
if (readcount < 0)
{
strmov(net->sqlstate, unknown_sqlstate);
net->last_errno=EE_READ; /* the errmsg for not entire file read */
my_snprintf(net->last_error,sizeof(net->last_error)-1,
tmp_name,errno);
goto err;
}
result=0; /* Ok */
err:
if (fd >= 0)
(void) my_close(fd,MYF(0));
my_free(buf,MYF(0));
DBUG_RETURN(result);
}
/**************************************************************************
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");
/* read from the actually used connection */
mysql = mysql->last_used_con;
if (!mysql->fields)
DBUG_RETURN(0);
if (mysql->status != MYSQL_STATUS_GET_RESULT)
{
strmov(mysql->net.sqlstate, unknown_sqlstate);
strmov(mysql->net.last_error,
ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
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))))
{
strmov(mysql->net.sqlstate, unknown_sqlstate);
mysql->net.last_errno=CR_OUT_OF_MEMORY;
strmov(mysql->net.last_error, ER(mysql->net.last_errno));
DBUG_RETURN(0);
}
result->eof=1; /* Marker for buffered */
result->lengths=(ulong*) (result+1);
if (!(result->data=read_rows(mysql,mysql->fields,mysql->field_count)))
{
my_free((gptr) 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;
result->current_field=0;
result->current_row=0; /* Must do a fetch first */
mysql->fields=0; /* fields is now in result */
DBUG_RETURN(result); /* Data fetched */
}
/************************************************************************** /**************************************************************************
Alloc struct for use with unbuffered reads. Data is fetched by domand Alloc struct for use with unbuffered reads. Data is fetched by domand
when calling to mysql_fetch_row. when calling to mysql_fetch_row.
...@@ -3096,76 +1004,6 @@ mysql_fetch_field(MYSQL_RES *result) ...@@ -3096,76 +1004,6 @@ mysql_fetch_field(MYSQL_RES *result)
return &result->fields[result->current_field++]; return &result->fields[result->current_field++];
} }
/**************************************************************************
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)
{
if (!(read_one_row(res->handle,res->field_count,res->row, res->lengths)))
{
res->row_count++;
DBUG_RETURN(res->current_row=res->row);
}
else
{
DBUG_PRINT("info",("end of data"));
res->eof=1;
res->handle->status=MYSQL_STATUS_READY;
/* Don't clear handle in mysql_free_results */
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.
**************************************************************************/
static void fetch_lengths(ulong *to, MYSQL_ROW column, uint field_count)
{
ulong *prev_length;
byte *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;
}
}
ulong * STDCALL ulong * STDCALL
mysql_fetch_lengths(MYSQL_RES *res) mysql_fetch_lengths(MYSQL_RES *res)
{ {
...@@ -3178,21 +1016,6 @@ mysql_fetch_lengths(MYSQL_RES *res) ...@@ -3178,21 +1016,6 @@ mysql_fetch_lengths(MYSQL_RES *res)
return res->lengths; return res->lengths;
} }
/**************************************************************************
Move to a specific row and column
**************************************************************************/
void STDCALL
mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
{
MYSQL_ROWS *tmp=0;
DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
if (result->data)
for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
result->current_row=0;
result->data_cursor = tmp;
}
/************************************************************************* /*************************************************************************
put the row or field cursor one a position one got from mysql_row_tell() put the row or field cursor one a position one got from mysql_row_tell()
This doesn't restore any data. The next mysql_fetch_row or This doesn't restore any data. The next mysql_fetch_row or
...@@ -3515,22 +1338,6 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg) ...@@ -3515,22 +1338,6 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
DBUG_RETURN(0); 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;
}
my_bool STDCALL mysql_eof(MYSQL_RES *res) my_bool STDCALL mysql_eof(MYSQL_RES *res)
{ {
return res->eof; return res->eof;
......
...@@ -43,14 +43,14 @@ sqlsources = derror.cc field.cc field_conv.cc filesort.cc \ ...@@ -43,14 +43,14 @@ sqlsources = derror.cc field.cc field_conv.cc filesort.cc \
item.cc item_buff.cc item_cmpfunc.cc item_create.cc \ item.cc item_buff.cc item_cmpfunc.cc item_create.cc \
item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \ item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \
item_uniq.cc item_subselect.cc item_row.cc\ item_uniq.cc item_subselect.cc item_row.cc\
key.cc lock.cc log.cc log_event.cc mf_iocache.cc\ key.cc lock.cc log.cc log_event.cc \
mini_client.cc protocol.cc net_serv.cc opt_ft.cc opt_range.cc \ protocol.cc net_serv.cc opt_ft.cc opt_range.cc \
opt_sum.cc procedure.cc records.cc sql_acl.cc \ opt_sum.cc procedure.cc records.cc sql_acl.cc \
repl_failsafe.cc slave.cc sql_load.cc sql_olap.cc \ sql_load.cc sql_olap.cc \
sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \ sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \
sql_crypt.cc sql_db.cc sql_delete.cc sql_error.cc sql_insert.cc \ sql_crypt.cc sql_db.cc sql_delete.cc sql_error.cc sql_insert.cc \
sql_lex.cc sql_list.cc sql_manager.cc sql_map.cc sql_parse.cc \ sql_lex.cc sql_list.cc sql_manager.cc sql_map.cc sql_parse.cc \
sql_prepare.cc sql_derived.cc sql_rename.cc sql_repl.cc \ sql_prepare.cc sql_derived.cc sql_rename.cc \
sql_select.cc sql_do.cc sql_show.cc set_var.cc \ sql_select.cc sql_do.cc sql_show.cc set_var.cc \
sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \ sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \
sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \ sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \
......
my_bool mysql_reconnect(MYSQL *mysql);
static my_bool send_file_to_server(MYSQL *mysql, const char *filename);
void end_server(MYSQL *mysql);
/****************************************************************************
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>
*****************************************************************************/
my_bool my_connect(my_socket s, const struct sockaddr *name,
uint namelen, uint timeout)
{
#if defined(__WIN__) || defined(OS2) || defined(__NETWARE__)
return connect(s, (struct sockaddr*) name, namelen) != 0;
#else
int flags, res, s_err;
SOCKOPT_OPTLEN_TYPE s_err_size = sizeof(uint);
fd_set sfds;
struct timeval tv;
time_t start_time, now_time;
/*
If they passed us a timeout of zero, we should behave
exactly like the normal connect() call does.
*/
if (timeout == 0)
return connect(s, (struct sockaddr*) name, namelen) != 0;
flags = fcntl(s, F_GETFL, 0); /* Set socket to not block */
#ifdef O_NONBLOCK
fcntl(s, F_SETFL, flags | O_NONBLOCK); /* and save the flags.. */
#endif
res = connect(s, (struct sockaddr*) name, namelen);
s_err = errno; /* Save the error... */
fcntl(s, F_SETFL, flags);
if ((res != 0) && (s_err != EINPROGRESS))
{
errno = s_err; /* Restore it */
return(1);
}
if (res == 0) /* Connected quickly! */
return(0);
/*
Otherwise, our connection is "in progress." We can use
the select() call to wait up to a specified period of time
for the connection to succeed. If select() returns 0
(after waiting howevermany seconds), our socket never became
writable (host is probably unreachable.) Otherwise, if
select() returns 1, then one of two conditions exist:
1. An error occured. We use getsockopt() to check for this.
2. The connection was set up sucessfully: getsockopt() will
return 0 as an error.
Thanks goes to Andrew Gierth <andrew@erlenstar.demon.co.uk>
who posted this method of timing out a connect() in
comp.unix.programmer on August 15th, 1997.
*/
FD_ZERO(&sfds);
FD_SET(s, &sfds);
/*
select could be interrupted by a signal, and if it is,
the timeout should be adjusted and the select restarted
to work around OSes that don't restart select and
implementations of select that don't adjust tv upon
failure to reflect the time remaining
*/
start_time = time(NULL);
for (;;)
{
tv.tv_sec = (long) timeout;
tv.tv_usec = 0;
#if defined(HPUX10) && defined(THREAD)
if ((res = select(s+1, NULL, (int*) &sfds, NULL, &tv)) > 0)
break;
#else
if ((res = select(s+1, NULL, &sfds, NULL, &tv)) > 0)
break;
#endif
if (res == 0) /* timeout */
return -1;
now_time=time(NULL);
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(s, 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
}
/*
Create a named pipe connection
*/
#ifdef __WIN__
HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
char **arg_unix_socket)
{
HANDLE hPipe=INVALID_HANDLE_VALUE;
char szPipeName [ 257 ];
DWORD dwMode;
int i;
my_bool testing_named_pipes=0;
char *host= *arg_host, *unix_socket= *arg_unix_socket;
#ifdef _libmysql_c
if ( ! unix_socket || (unix_socket)[0] == 0x00)
unix_socket = mysql_unix_port;
#endif
if (!host || !strcmp(host,LOCAL_HOST))
host=LOCAL_HOST_NAMEDPIPE;
sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
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(szPipeName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL )) != INVALID_HANDLE_VALUE)
break;
if (GetLastError() != ERROR_PIPE_BUSY)
{
net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
(ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
/* wait for for an other instance */
if (! WaitNamedPipe(szPipeName, connect_timeout*1000) )
{
net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
(ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
}
if (hPipe == INVALID_HANDLE_VALUE)
{
net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
(ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
{
CloseHandle( hPipe );
net->last_errno=CR_NAMEDPIPESETSTATE_ERROR;
sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
(ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
*arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
return (hPipe);
}
#endif
/*****************************************************************************
Read a packet from server. Give error message if socket was down
or packet is an error message
*****************************************************************************/
ulong
net_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: %d",
vio_description(net->vio),len));
end_server(mysql);
net->last_errno=(net->last_errno == ER_NET_PACKET_TOO_LARGE ?
CR_NET_PACKET_TOO_LARGE:
CR_SERVER_LOST);
strmov(net->last_error,ER(net->last_errno));
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;
(void) strmake(net->last_error,(char*) pos,
min((uint) len,(uint) sizeof(net->last_error)-1));
}
else
{
net->last_errno=CR_UNKNOWN_ERROR;
(void) strmov(net->last_error,ER(net->last_errno));
}
DBUG_PRINT("error",("Got error: %d (%s)", net->last_errno,
net->last_error));
return(packet_error);
}
return len;
}
static void free_rows(MYSQL_DATA *cur)
{
if (cur)
{
free_root(&cur->alloc,MYF(0));
my_free((gptr) cur,MYF(0));
}
}
static my_bool
advanced_command(MYSQL *mysql, enum enum_server_command command,
const char *header, ulong header_length,
const char *arg, ulong arg_length, my_bool skip_check)
{
NET *net= &mysql->net;
my_bool result= 1;
init_sigpipe_variables
/* 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))
return 1;
}
if (mysql->status != MYSQL_STATUS_READY)
{
strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
return 1;
}
mysql->net.last_error[0]=0;
mysql->net.last_errno=0;
mysql->net.report_error=0;
mysql->info=0;
mysql->affected_rows= ~(my_ulonglong) 0;
net_clear(&mysql->net); /* Clear receive buffer */
if (!arg)
arg="";
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)
{
net->last_errno=CR_NET_PACKET_TOO_LARGE;
strmov(net->last_error,ER(net->last_errno));
goto end;
}
end_server(mysql);
if (mysql_reconnect(mysql))
goto end;
if (net_write_command(net,(uchar) command, header, header_length,
arg, arg_length))
{
net->last_errno=CR_SERVER_GONE_ERROR;
strmov(net->last_error,ER(net->last_errno));
goto end;
}
}
result=0;
if (!skip_check)
result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ?
1 : 0);
end:
reset_sigpipe(mysql);
return result;
}
my_bool
simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
ulong length, my_bool skip_check)
{
return advanced_command(mysql, command, NullS, 0, arg, length, skip_check);
}
static void free_old_query(MYSQL *mysql)
{
DBUG_ENTER("free_old_query");
if (mysql->fields)
free_root(&mysql->field_alloc,MYF(0));
else
init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
mysql->fields=0;
mysql->field_count=0; /* For API */
DBUG_VOID_RETURN;
}
#ifdef __WIN__
static my_bool is_NT(void)
{
char *os=getenv("OS");
return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
}
#endif
/**************************************************************************
Shut down connection
**************************************************************************/
void end_server(MYSQL *mysql)
{
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);
DBUG_VOID_RETURN;
}
void STDCALL
mysql_free_result(MYSQL_RES *result)
{
DBUG_ENTER("mysql_free_result");
DBUG_PRINT("enter",("mysql_res: %lx",result));
if (result)
{
if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
{
DBUG_PRINT("warning",("Not all rows in set where read; Ignoring rows"));
for (;;)
{
ulong pkt_len;
if ((pkt_len=net_safe_read(result->handle)) == packet_error)
break;
if (pkt_len <= 8 && result->handle->net.read_pos[0] == 254)
break; /* End of data */
}
result->handle->status=MYSQL_STATUS_READY;
}
free_rows(result->data);
if (result->fields)
free_root(&result->field_alloc,MYF(0));
if (result->row)
my_free((gptr) result->row,MYF(0));
my_free((gptr) result,MYF(0));
}
DBUG_VOID_RETURN;
}
#ifdef _libmysql_c
/****************************************************************************
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",
"replication-probe", "enable-reads-from-master", "repl-parse-query",
"ssl-cipher", "max-allowed-packet",
"protocol", "shared-memory-base-name",
NullS
};
static TYPELIB option_types={array_elements(default_options)-1,
"options",default_options};
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*),0,5 CALLER_INFO);
}
if (!(tmp= my_strdup(cmd,MYF(MY_WME))) ||
insert_dynamic(options->init_commands, (gptr)&tmp))
{
my_free(tmp, MYF(MY_ALLOW_ZERO_PTR));
return 1;
}
return 0;
}
static 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;
load_defaults(filename, groups, &argc, &argv);
if (argc != 1) /* If some default option */
{
char **option=argv;
while (*++option)
{
/* 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 */
mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace");
break;
case 12: /* return-found-rows */
options->client_flag|=CLIENT_FOUND_ROWS;
break;
#ifdef HAVE_OPENSSL
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;
#else
case 13: /* Ignore SSL options */
case 14:
case 15:
case 16:
break;
#endif /* HAVE_OPENSSL */
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 23: /* replication probe */
options->rpl_probe= 1;
break;
case 24: /* enable-reads-from-master */
options->no_master_reads= 0;
break;
case 25: /* repl-parse-query */
options->rpl_parse= 1;
break;
case 27:
options->max_allowed_packet= atoi(opt_arg);
break;
case 28: /* protocol */
if ((options->protocol = find_type(opt_arg, &sql_protocol_typelib,0)) == ~(ulong) 0)
{
fprintf(stderr, "Unknown option to protocol: %s\n", opt_arg);
exit(1);
}
break;
case 29: /* 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;
default:
DBUG_PRINT("warning",("unknown option: %s",option[0]));
}
}
}
}
free_defaults(argv);
DBUG_VOID_RETURN;
}
#endif /*_libmysql_c*/
/**************************************************************************
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 fetch_lengths(ulong *to, MYSQL_ROW column, uint field_count)
{
ulong *prev_length;
byte *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;
}
}
static inline void
unpack_fields_40(MYSQL_ROWS *row, MYSQL_FIELD *field, MEM_ROOT *alloc,
ulong *lengths, uint n_lengths,
my_bool default_value, my_bool long_flag_protocol)
{
DBUG_ENTER("unpack_fields_40");
for (; row ; row = row->next,field++)
{
fetch_lengths(lengths, row->data, n_lengths);
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->org_table_length= field->table_length= lengths[0];
field->name_length= lengths[1];
if (long_flag_protocol)
{
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;
}
}
/***************************************************************************
Change field rows to field structs
***************************************************************************/
static 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[8]; /* Max of fields */
DBUG_ENTER("unpack_fields");
field=result=(MYSQL_FIELD*) alloc_root(alloc,
(uint) sizeof(MYSQL_FIELD)*fields);
if (!result)
{
free_rows(data); /* Free old data */
DBUG_RETURN(0);
}
bzero((char*) field, (uint) sizeof(MYSQL_FIELD)*fields);
#ifdef _mini_client_c
unpack_fields_40(data->data, field, alloc, lengths, default_value ? 6 : 5,
default_value, server_capabilities & CLIENT_LONG_FLAG);
#else
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;
fetch_lengths(&lengths[0], row->data, default_value ? 7 : 6);
field->db = strdup_root(alloc,(char*) row->data[0]);
field->table = strdup_root(alloc,(char*) row->data[1]);
field->org_table= strdup_root(alloc,(char*) row->data[2]);
field->name = strdup_root(alloc,(char*) row->data[3]);
field->org_name = strdup_root(alloc,(char*) row->data[4]);
field->db_length= lengths[0];
field->table_length= lengths[1];
field->org_table_length= lengths[2];
field->name_length= lengths[3];
field->org_name_length= lengths[4];
/* Unpack fixed length parts */
pos= (uchar*) row->data[5];
field->charsetnr= uint2korr(pos);
field->length= (uint) uint3korr(pos+2);
field->type= (enum enum_field_types) pos[5];
field->flags= uint2korr(pos+6);
field->decimals= (uint) pos[8];
if (INTERNAL_NUM_FIELD(field))
field->flags|= NUM_FLAG;
if (default_value && row->data[6])
{
field->def=strdup_root(alloc,(char*) row->data[6]);
field->def_length= lengths[6];
}
else
field->def=0;
field->max_length= 0;
}
}
#ifndef DELETE_SUPPORT_OF_4_0_PROTOCOL
else
unpack_fields_40(data->data, field, alloc, lengths, default_value ? 6 : 5,
default_value, server_capabilities & CLIENT_LONG_FLAG);
#endif /* DELETE_SUPPORT_OF_4_0_PROTOCOL */
#endif /*_mini_client_c*/
free_rows(data); /* Free old data */
DBUG_RETURN(result);
}
/* Read all rows (fields or data) from server */
static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
uint 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("read_rows");
if ((pkt_len= net_safe_read(mysql)) == packet_error)
DBUG_RETURN(0);
if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
MYF(MY_WME | MY_ZEROFILL))))
{
net->last_errno=CR_OUT_OF_MEMORY;
strmov(net->last_error,ER(net->last_errno));
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);
net->last_errno=CR_OUT_OF_MEMORY;
strmov(net->last_error,ER(net->last_errno));
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);
net->last_errno=CR_MALFORMED_PACKET;
strmov(net->last_error,ER(net->last_errno));
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=net_safe_read(mysql)) == packet_error)
{
free_rows(result);
DBUG_RETURN(0);
}
}
*prev_ptr=0; /* last pointer is null */
#ifndef _mini_client_c
if (pkt_len > 1) /* MySQL 4.1 protocol */
{
mysql->warning_count= uint2korr(cp+1);
DBUG_PRINT("info",("warning_count: %ld", mysql->warning_count));
}
#endif
DBUG_PRINT("exit",("Got %d rows",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;
if ((pkt_len=net_safe_read(mysql)) == packet_error)
return -1;
if (pkt_len <= 8 && mysql->net.read_pos[0] == 254)
{
#ifndef _mini_client_c
if (pkt_len > 1) /* MySQL 4.1 protocol */
mysql->warning_count= uint2korr(mysql->net.read_pos+1);
#endif
return 1; /* End of data */
}
prev_pos= 0; /* allowed to write at packet[-1] */
pos=mysql->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))
{
mysql->net.last_errno=CR_UNKNOWN_ERROR;
strmov(mysql->net.last_error,ER(mysql->net.last_errno));
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)
{
mysql_once_init();
if (!mysql)
{
if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
return 0;
mysql->free_me=1;
}
else
bzero((char*) (mysql),sizeof(*(mysql)));
#ifndef _mini_client_c
mysql->options.connect_timeout=CONNECT_TIMEOUT;
mysql->last_used_con = mysql->next_slave = mysql->master = mysql;
/*
By default, we are a replication pivot. The caller must reset it
after we return if this is not the case.
*/
mysql->rpl_pivot = 1;
#if defined(SIGPIPE) && defined(THREAD) && !defined(__WIN__)
if (!((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE))
(void) signal(SIGPIPE,pipe_sig_handler);
#endif
/*
Only enable LOAD DATA INFILE by default if configured with
--enable-local-infile
*/
#ifdef ENABLED_LOCAL_INFILE
mysql->options.client_flag|= CLIENT_LOCAL_FILES;
#endif
#ifdef HAVE_SMEM
mysql->options.shared_memory_base_name=(char*)def_shared_memory_base_name;
#endif
#else /*_mini_client_c*/
#ifdef __WIN__
mysql->options.connect_timeout=20;
#endif
mysql->net.read_timeout = slave_net_timeout;
#endif /*_mini_client_c*/
return mysql;
}
/*
Initialize the MySQL library
SYNOPSIS
mysql_once_init()
NOTES
Can't be static on NetWare
This function is called by mysql_init() and indirectly called
by mysql_query(), so one should never have to call this from an
outside program.
*/
void mysql_once_init(void)
{
#ifndef _mini_client_c
if (!mysql_client_init)
{
mysql_client_init=1;
org_my_init_done=my_init_done;
my_init(); /* Will init threads */
init_client_errs();
if (!mysql_port)
{
mysql_port = MYSQL_PORT;
#ifndef MSDOS
{
struct servent *serv_ptr;
char *env;
if ((serv_ptr = getservbyname("mysql", "tcp")))
mysql_port = (uint) ntohs((ushort) serv_ptr->s_port);
if ((env = getenv("MYSQL_TCP_PORT")))
mysql_port =(uint) atoi(env);
}
#endif
}
if (!mysql_unix_port)
{
char *env;
#ifdef __WIN__
mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
#else
mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
#endif
if ((env = getenv("MYSQL_UNIX_PORT")))
mysql_unix_port = env;
}
mysql_debug(NullS);
#if defined(SIGPIPE) && !defined(THREAD) && !defined(__WIN__)
(void) signal(SIGPIPE,SIG_IGN);
#endif
}
#ifdef THREAD
else
my_thread_init(); /* Init if new thread */
#endif
#else /*_mini_client_c*/
init_client_errs();
#endif /*_mini_client_c*/
}
/*
Handle password authentication
*/
static my_bool mysql_autenticate(MYSQL *mysql, const char *passwd)
{
ulong pkt_length;
NET *net= &mysql->net;
char buff[SCRAMBLE41_LENGTH];
char password_hash[SCRAMBLE41_LENGTH]; /* Used for storage of stage1 hash */
/* We shall only query server if it expect us to do so */
if ((pkt_length=net_safe_read(mysql)) == packet_error)
goto error;
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
/*
This should always happen with new server unless empty password
OK/Error packets have zero as the first char
*/
if (pkt_length == 24 && net->read_pos[0])
{
/* Old passwords will have '*' at the first byte of hash */
if (net->read_pos[0] != '*')
{
/* Build full password hash as it is required to decode scramble */
password_hash_stage1(buff, passwd);
/* Store copy as we'll need it later */
memcpy(password_hash,buff,SCRAMBLE41_LENGTH);
/* Finally hash complete password using hash we got from server */
password_hash_stage2(password_hash,(const char*) net->read_pos);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((const char*) net->read_pos+4,mysql->scramble_buff,
password_hash, SCRAMBLE41_LENGTH);
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
/* Encode scramble with password. Recycle buffer */
password_crypt(mysql->scramble_buff,buff,buff,SCRAMBLE41_LENGTH);
}
else
{
/* Create password to decode scramble */
create_key_from_old_password(passwd,password_hash);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((const char*) net->read_pos+4,mysql->scramble_buff,
password_hash, SCRAMBLE41_LENGTH);
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
/* Finally scramble decoded scramble with password */
scramble(buff, mysql->scramble_buff, passwd,0);
}
/* Write second package of authentication */
if (my_net_write(net,buff,SCRAMBLE41_LENGTH) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Read what server thinks about out new auth message report */
if (net_safe_read(mysql) == packet_error)
goto error;
}
}
return 0;
error:
return 1;
}
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
struct passwd *getpwuid(uid_t);
char* getlogin(void);
#endif
#if defined(__NETWARE__)
/* default to "root" on NetWare */
static void read_user_name(char *name)
{
char *str=getenv("USER");
strmake(name, str ? str : "UNKNOWN_USER", USERNAME_LENGTH);
}
#elif !defined(MSDOS) && ! defined(VMS) && !defined(__WIN__) && !defined(OS2)
static void read_user_name(char *name)
{
DBUG_ENTER("read_user_name");
if (geteuid() == 0)
(void) strmov(name,"root"); /* allow use of surun */
else
{
#ifdef HAVE_GETPWUID
struct passwd *skr;
const char *str;
if ((str=getlogin()) == NULL)
{
if ((skr=getpwuid(geteuid())) != NULL)
str=skr->pw_name;
else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) &&
!(str=getenv("LOGIN")))
str="UNKNOWN_USER";
}
(void) strmake(name,str,USERNAME_LENGTH);
#elif HAVE_CUSERID
(void) cuserid(name);
#else
strmov(name,"UNKNOWN_USER");
#endif
}
DBUG_VOID_RETURN;
}
#else /* If MSDOS || VMS */
static void read_user_name(char *name)
{
char *str=getenv("USER"); /* ODBC will send user variable */
strmake(name,str ? str : "ODBC", USERNAME_LENGTH);
}
#endif
/*
Note that the mysql argument must be initialized with mysql_init()
before calling mysql_real_connect !
*/
MYSQL * STDCALL
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
#ifdef _mini_client_c
, uint net_read_timeout
#endif
)
{
char buff[NAME_LEN+USERNAME_LENGTH+100],charset_name_buff[16];
char *end,*host_info,*charset_name;
my_socket sock;
uint32 ip_addr;
struct sockaddr_in sock_addr;
ulong pkt_length;
NET *net= &mysql->net;
#ifdef _mini_client_c
thr_alarm_t alarmed;
ALARM alarm_buff;
ulong max_allowed_packet;
#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)"));
/* Don't give sigpipe errors if the client doesn't want them */
set_sigpipe(mysql);
net->vio = 0; /* If something goes wrong */
#ifdef _mini_client_c
mysql->charset=default_charset_info; /* Set character set */
#endif
#ifdef _libmysql_c
/* 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 (!passwd)
{
passwd=mysql->options.password;
#ifndef DONT_USE_MYSQL_PWD
if (!passwd)
passwd=getenv("MYSQL_PWD"); /* get it from environment */
#endif
}
if (!db || !db[0])
db=mysql->options.db;
if (!port)
port=mysql->options.port;
if (!unix_socket)
unix_socket=mysql->options.unix_socket;
#endif /*_libmysql_c*/
#ifdef _mini_client_c
if (!port)
port = MYSQL_PORT; /* Should always be set by mysqld */
if (!unix_socket)
unix_socket=MYSQL_UNIX_ADDR;
if (!mysql->options.connect_timeout)
mysql->options.connect_timeout= net_read_timeout;
#endif /*mini_client_c*/
mysql->reconnect=1; /* Reconnect as default */
mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
/*
Grab a socket and connect it to the server
*/
#if defined(_libmysql_c) && 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 */
}
else
{
mysql->options.protocol=MYSQL_PROTOCOL_MEMORY;
sock=0;
unix_socket = 0;
host=mysql->options.shared_memory_base_name;
host_info=(char*) ER(CR_SHARED_MEMORY_CONNECTION);
}
} else
#endif /* HAVE_SMEM */
#if defined(HAVE_SYS_UN_H)
if (
#ifdef _libmysql_c
(!mysql->options.protocol ||
mysql->options.protocol == MYSQL_PROTOCOL_SOCKET)&&
(unix_socket || mysql_unix_port) &&
#endif
#ifdef _mini_client_c
unix_socket &&
#endif
(!host || !strcmp(host,LOCAL_HOST)))
{
host=LOCAL_HOST;
#ifdef _libmysql_c
if (!unix_socket)
unix_socket=mysql_unix_port;
#endif
host_info=(char*) ER(CR_LOCALHOST_CONNECTION);
DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
{
net->last_errno=CR_SOCKET_CREATE_ERROR;
sprintf(net->last_error,ER(net->last_errno),socket_errno);
goto error;
}
net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
UNIXaddr.sun_family = AF_UNIX;
strmov(UNIXaddr.sun_path, unix_socket);
if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
mysql->options.connect_timeout))
{
DBUG_PRINT("error",("Got error %d on connect to local server",
socket_errno));
net->last_errno=CR_CONNECTION_ERROR;
sprintf(net->last_error,ER(net->last_errno),unix_socket,socket_errno);
goto error;
}
#ifdef _libmysql_c
else
mysql->options.protocol=MYSQL_PROTOCOL_SOCKET;
#endif
}
else
#elif defined(__WIN__)
{
#ifdef _libmysql_c
if ((!mysql->options.protocol ||
mysql->options.protocol == MYSQL_PROTOCOL_PIPE)&&
((unix_socket || !host && is_NT() ||
host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||! have_tcpip))&&
(!net->vio))
#elif _mini_client_c
if ((unix_socket ||
!host && is_NT() ||
host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||
mysql->options.named_pipe || !have_tcpip))
#endif
{
sock=0;
if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
(char**) &host, (char**) &unix_socket)) ==
INVALID_HANDLE_VALUE)
{
DBUG_PRINT("error",
("host: '%s' socket: '%s' have_tcpip: %d",
host ? host : "<null>",
unix_socket ? unix_socket : "<null>",
(int) have_tcpip));
if (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
(host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
(unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
goto error;
/* Try also with TCP/IP */
}
else
{
net->vio=vio_new_win32pipe(hPipe);
sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host,
unix_socket);
}
}
}
#ifdef _mini_client_c
if (hPipe == INVALID_HANDLE_VALUE)
#endif
#endif
#ifdef _libmysql_c
if ((!mysql->options.protocol ||
mysql->options.protocol == MYSQL_PROTOCOL_TCP)&&(!net->vio))
#endif
{
unix_socket=0; /* This is not used */
#ifdef _libmysql_c
if (!port)
port=mysql_port;
#endif
if (!host)
host=LOCAL_HOST;
sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
#ifdef _mini_client_c
thr_alarm_init(&alarmed);
thr_alarm(&alarmed, net_read_timeout, &alarm_buff);
#endif
sock = (my_socket) socket(AF_INET,SOCK_STREAM,0);
#ifdef _mini_client_c
thr_end_alarm(&alarmed);
#endif
/* _WIN64 ; Assume that the (int) range is enough for socket() */
if (sock == SOCKET_ERROR)
{
net->last_errno=CR_IPSOCK_ERROR;
sprintf(net->last_error,ER(net->last_errno),socket_errno);
goto error;
}
net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
bzero((char*) &sock_addr,sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
/*
The server name may be a host name or IP address
*/
if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE)
{
memcpy_fixed(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr));
}
else
{
int tmp_errno;
struct hostent tmp_hostent,*hp;
char buff2[GETHOSTBYNAME_BUFF_SIZE];
hp = my_gethostbyname_r(host,&tmp_hostent,buff2,sizeof(buff2),
&tmp_errno);
if (!hp)
{
my_gethostbyname_r_free();
net->last_errno=CR_UNKNOWN_HOST;
sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, tmp_errno);
goto error;
}
memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
my_gethostbyname_r_free();
}
sock_addr.sin_port = (ushort) htons((ushort) port);
if (my_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
mysql->options.connect_timeout))
{
DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,
host));
net->last_errno= CR_CONN_HOST_ERROR;
sprintf(net->last_error ,ER(CR_CONN_HOST_ERROR), host, socket_errno);
goto error;
}
}
#ifdef _libmysql_c
else if (!net->vio)
{
DBUG_PRINT("error",("Unknow protocol %d ",mysql->options.protocol));
net->last_errno= CR_CONN_UNKNOW_PROTOCOL;
sprintf(net->last_error ,ER(CR_CONN_UNKNOW_PROTOCOL));
goto error;
}
#endif /*_libmysql_c*/
if (!net->vio || my_net_init(net, net->vio))
{
vio_delete(net->vio);
net->vio = 0;
net->last_errno=CR_OUT_OF_MEMORY;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
vio_keepalive(net->vio,TRUE);
#ifdef _mini_client_c
net->read_timeout=slave_net_timeout;
#endif
/* Get version info */
mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
if (mysql->options.connect_timeout &&
vio_poll_read(net->vio, mysql->options.connect_timeout))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
if ((pkt_length=net_safe_read(mysql)) == packet_error)
goto error;
/* Check if version of protocol matches current one */
mysql->protocol_version= net->read_pos[0];
DBUG_DUMP("packet",(char*) net->read_pos,10);
DBUG_PRINT("info",("mysql protocol version %d, server=%d",
PROTOCOL_VERSION, mysql->protocol_version));
if (mysql->protocol_version != PROTOCOL_VERSION
#ifdef _mini_client_c
&& mysql->protocol_version != PROTOCOL_VERSION-1
#endif
)
{
net->last_errno= CR_VERSION_ERROR;
sprintf(net->last_error, 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;
strmake(mysql->scramble_buff,end,8);
end+=9;
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);
}
#ifdef _libmysql_c
/* Set character set */
if ((charset_name=mysql->options.charset_name))
{
const char *save=charsets_dir;
if (mysql->options.charset_dir)
charsets_dir=mysql->options.charset_dir;
mysql->charset=get_charset_by_name(mysql->options.charset_name,
MYF(MY_WME));
charsets_dir=save;
}
else if (mysql->server_language)
{
charset_name=charset_name_buff;
sprintf(charset_name,"%d",mysql->server_language); /* In case of errors */
if (!(mysql->charset =
get_charset((uint8) mysql->server_language, MYF(0))))
mysql->charset = default_charset_info; /* shouldn't be fatal */
}
else
mysql->charset=default_charset_info;
if (!mysql->charset)
{
net->last_errno=CR_CANT_READ_CHARSET;
if (mysql->options.charset_dir)
sprintf(net->last_error,ER(net->last_errno),
charset_name ? charset_name : "unknown",
mysql->options.charset_dir);
else
{
char cs_dir_name[FN_REFLEN];
get_charsets_dir(cs_dir_name);
sprintf(net->last_error,ER(net->last_errno),
charset_name ? charset_name : "unknown",
cs_dir_name);
}
goto error;
}
#endif /*_libmysql_c*/
/* Save connection information */
if (!user) user="";
if (!passwd) passwd="";
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))))
{
strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY));
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;
client_flag|=mysql->options.client_flag;
/* Send client information for access check */
client_flag|=CLIENT_CAPABILITIES;
#ifdef HAVE_OPENSSL
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 */
if (db)
client_flag|=CLIENT_CONNECT_WITH_DB;
#ifdef _libmysql_c
/* 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 4 byte option flag */
int4store(buff,client_flag);
int4store(buff+4,max_allowed_packet);
end= buff+8;
}
else
{
int2store(buff,client_flag);
int3store(buff+2,max_allowed_packet);
end= buff+5;
}
mysql->client_flag=client_flag;
#endif /*_libmysql_c*/
#ifdef _mini_client_c
#ifdef HAVE_COMPRESS
if ((mysql->server_capabilities & CLIENT_COMPRESS) &&
(mysql->options.compress || (client_flag & CLIENT_COMPRESS)))
client_flag|=CLIENT_COMPRESS; /* We will use compression */
else
#endif
client_flag&= ~CLIENT_COMPRESS;
#endif /*mini_client_c*/
#ifdef _mini_client_c
#ifdef HAVE_OPENSSL
if ((mysql->server_capabilities & CLIENT_SSL) &&
(mysql->options.use_ssl || (client_flag & CLIENT_SSL)))
{
DBUG_PRINT("info", ("Changing IO layer to SSL"));
client_flag |= CLIENT_SSL;
}
else
{
if (client_flag & CLIENT_SSL)
{
DBUG_PRINT("info", ("Leaving IO layer intact because server doesn't support SSL"));
}
client_flag &= ~CLIENT_SSL;
}
#endif /* HAVE_OPENSSL */
max_allowed_packet=mysql->net.max_packet_size;
int2store(buff,client_flag);
int3store(buff+2,max_allowed_packet);
end= buff+5;
mysql->client_flag=client_flag;
#endif /*_mini_client_c*/
#ifdef HAVE_OPENSSL
/*
Oops.. are we careful enough to not send ANY information without
encryption?
*/
if (client_flag & CLIENT_SSL)
{
struct st_mysql_options *options= &mysql->options;
if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Do the SSL layering. */
#ifdef _libmysql_c
if (!(mysql->connector_fd=
(gptr) new_VioSSLConnectorFd(options->ssl_key,
options->ssl_cert,
options->ssl_ca,
options->ssl_capath,
options->ssl_cipher)))
{
net->last_errno= CR_SSL_CONNECTION_ERROR;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
#endif /*libmysql_c*/
DBUG_PRINT("info", ("IO layer change in progress..."));
if (sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd),
mysql->net.vio, (long) (mysql->options.connect_timeout)))
{
net->last_errno= CR_SSL_CONNECTION_ERROR;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
DBUG_PRINT("info", ("IO layer change done!"));
}
#endif /* HAVE_OPENSSL */
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,32); /* Max user name */
else
#ifdef _mini_client_c
{
user = getenv("USER");
if (!user) user = "mysql";
strmov((char*) end, user );
}
#else
read_user_name((char*) end);
#endif /*_mini_client_c*/
/* We have to handle different version of handshake here */
#if defined(_CUSTOMCONFIG_) && defined(_libmysql_c)
#include "_cust_libmysql.h";
#endif
DBUG_PRINT("info",("user: %s",end));
/*
We always start with old type handshake the only difference is message sent
If server handles secure connection type we'll not send the real scramble
*/
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
if (passwd[0])
{
/* Prepare false scramble */
end=strend(end)+1;
bfill(end, SCRAMBLE_LENGTH, 'x');
end+=SCRAMBLE_LENGTH;
*end=0;
}
else /* For empty password*/
{
end=strend(end)+1;
*end=0; /* Store zero length scramble */
}
}
else
{
/*
Real scramble is only sent to old servers. This can be blocked
by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1);
*/
end=scramble(strend(end)+1, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
}
/* Add database if needed */
if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
{
end=strmake(end+1,db,NAME_LEN);
mysql->db=my_strdup(db,MYF(MY_WME));
db=0;
}
/* Write authentication package */
if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
if (mysql_autenticate(mysql, passwd))
goto error;
if (client_flag & CLIENT_COMPRESS) /* We will use compression */
net->compress=1;
#ifdef _libmysql_c
if (mysql->options.max_allowed_packet)
net->max_packet_size= mysql->options.max_allowed_packet;
if (db && mysql_select_db(mysql,db))
goto error;
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;
my_bool reconnect=mysql->reconnect;
mysql->reconnect=0;
for (; ptr<end; ptr++)
{
MYSQL_RES *res;
if (mysql_query(mysql,*ptr))
goto error;
if (mysql->fields)
{
if (!(res= mysql_use_result(mysql)))
goto error;
mysql_free_result(res);
}
}
mysql->reconnect=reconnect;
}
if (mysql->options.rpl_probe && mysql_rpl_probe(mysql))
goto error;
#endif /*_libmysql_c*/
DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
reset_sigpipe(mysql);
DBUG_RETURN(mysql);
error:
reset_sigpipe(mysql);
DBUG_PRINT("error",("message: %u (%s)",net->last_errno,net->last_error));
{
/* Free alloced memory */
my_bool free_me=mysql->free_me;
end_server(mysql);
mysql->free_me=0;
mysql_close(mysql);
mysql->free_me=free_me;
}
DBUG_RETURN(0);
}
/* needed when we move MYSQL structure to a different address */
static void mysql_fix_pointers(MYSQL* mysql, MYSQL* old_mysql)
{
MYSQL *tmp, *tmp_prev;
if (mysql->master == old_mysql)
mysql->master = mysql;
if (mysql->last_used_con == old_mysql)
mysql->last_used_con = mysql;
if (mysql->last_used_slave == old_mysql)
mysql->last_used_slave = mysql;
for (tmp_prev = mysql, tmp = mysql->next_slave;
tmp != old_mysql;tmp = tmp->next_slave)
{
tmp_prev = tmp;
}
tmp_prev->next_slave = mysql;
}
my_bool mysql_reconnect(MYSQL *mysql)
{
MYSQL tmp_mysql;
DBUG_ENTER("mysql_reconnect");
if (!mysql->reconnect
#ifdef _libmysql_c
|| (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info
#endif
)
{
/* Allow reconnect next time */
#ifdef _libmysql_c
mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
#endif
mysql->net.last_errno=CR_SERVER_GONE_ERROR;
strmov(mysql->net.last_error,ER(mysql->net.last_errno));
DBUG_RETURN(1);
}
mysql_init(&tmp_mysql);
tmp_mysql.options=mysql->options;
bzero((char*) &mysql->options,sizeof(mysql->options));
tmp_mysql.rpl_pivot = mysql->rpl_pivot;
if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
mysql->db, mysql->port, mysql->unix_socket,
mysql->client_flag
#ifdef _mini_client_c
, mysql->net.read_timeout
#endif
))
{
mysql->net.last_errno= tmp_mysql.net.last_errno;
strmov(mysql->net.last_error, tmp_mysql.net.last_error);
DBUG_RETURN(1);
}
tmp_mysql.free_me=mysql->free_me;
mysql->free_me=0;
mysql_close(mysql);
*mysql=tmp_mysql;
#ifdef _libmysql_c
mysql_fix_pointers(mysql, &tmp_mysql); /* adjust connection pointers */
#endif
net_clear(&mysql->net);
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,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);
}
/*
Free strings in the SSL structure and clear 'use_ssl' flag.
NB! Errors are not reported until you do mysql_real_connect.
*/
#ifdef HAVE_OPENSSL
static void
mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
{
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));
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;
}
#endif /* HAVE_OPENSSL */
/*************************************************************************
Send a QUIT to the server and close the connection
If handle is alloced by mysql connect free it.
*************************************************************************/
void STDCALL
mysql_close(MYSQL *mysql)
{
DBUG_ENTER("mysql_close");
if (mysql) /* Some simple safety */
{
if (mysql->net.vio != 0)
{
free_old_query(mysql);
mysql->status=MYSQL_STATUS_READY; /* Force command */
mysql->reconnect=0;
simple_command(mysql,COM_QUIT,NullS,0,1);
end_server(mysql); /* Sets mysql->net.vio= 0 */
}
my_free((gptr) 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));
#ifdef _libmysql_c
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));
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));
}
#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 */
/* free/close slave list */
if (mysql->rpl_pivot)
{
MYSQL* tmp;
for (tmp = mysql->next_slave; tmp != mysql; )
{
/* trick to avoid following freed pointer */
MYSQL* tmp1 = tmp->next_slave;
mysql_close(tmp);
tmp = tmp1;
}
mysql->rpl_pivot=0;
}
if (mysql->stmts)
{
/* Free any open prepared statements */
LIST *element, *next_element;
for (element= mysql->stmts; element; element= next_element)
{
next_element= element->next;
stmt_close((MYSQL_STMT *)element->data, 0);
}
}
if (mysql != mysql->master)
mysql_close(mysql->master);
#endif /*_libmysql_c*/
#ifdef HAVE_OPENSSL
mysql_ssl_free(mysql);
#endif /* HAVE_OPENSSL */
/* Clear pointers for better safety */
mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
bzero((char*) &mysql->options,sizeof(mysql->options));
if (mysql->free_me)
my_free((gptr) mysql,MYF(0));
}
DBUG_VOID_RETURN;
}
my_bool STDCALL mysql_read_query_result(MYSQL *mysql)
{
uchar *pos;
ulong field_count;
MYSQL_DATA *fields;
ulong length;
DBUG_ENTER("mysql_read_query_result");
#ifdef _libmysql_c
/*
Read from the connection which we actually used, which
could differ from the original connection if we have slaves
*/
mysql = mysql->last_used_con;
#endif
if ((length = net_safe_read(mysql)) == packet_error)
DBUG_RETURN(1);
free_old_query(mysql); /* Free old result */
get_info:
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);
#ifdef _libmysql_c
if (protocol_41(mysql))
{
mysql->server_status=uint2korr(pos); pos+=2;
mysql->warning_count=uint2korr(pos); pos+=2;
}
else
#endif /*libmysql_c*/
if (mysql->server_capabilities & CLIENT_TRANSACTIONS)
{
mysql->server_status=uint2korr(pos); pos+=2;
mysql->warning_count= 0;
}
DBUG_PRINT("info",("status: %ld warning_count: %ld",
mysql->server_status, mysql->warning_count));
if (pos < mysql->net.read_pos+length && net_field_length(&pos))
mysql->info=(char*) pos;
DBUG_RETURN(0);
}
if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
{
int error=send_file_to_server(mysql,(char*) pos);
if ((length=net_safe_read(mysql)) == packet_error || error)
DBUG_RETURN(1);
goto get_info; /* Get info packet */
}
if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
mysql->server_status|= SERVER_STATUS_IN_TRANS;
mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
if (!(fields=read_rows(mysql,(MYSQL_FIELD*)0,
#ifdef _libmysql_c
protocol_41(mysql) ? 6 :
#endif
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;
mysql->warning_count= 0;
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_PRINT("enter",("rpl_parse: %d rpl_pivot: %d",
mysql->options.rpl_parse, mysql->rpl_pivot));
#ifdef _libmysql_c
if (mysql->options.rpl_parse && mysql->rpl_pivot)
{
switch (mysql_rpl_query_type(query, length)) {
case MYSQL_RPL_MASTER:
DBUG_RETURN(mysql_master_send_query(mysql, query, length));
case MYSQL_RPL_SLAVE:
DBUG_RETURN(mysql_slave_send_query(mysql, query, length));
case MYSQL_RPL_ADMIN:
break; /* fall through */
}
}
mysql->last_used_con = mysql;
#endif /*libmysql_c*/
DBUG_RETURN(simple_command(mysql, COM_QUERY, query, length, 1));
}
int STDCALL
mysql_real_query(MYSQL *mysql, const char *query, ulong length)
{
DBUG_ENTER("mysql_real_query");
DBUG_PRINT("enter",("handle: %lx",mysql));
DBUG_PRINT("query",("Query = '%-.4096s'",query));
if (mysql_send_query(mysql,query,length))
DBUG_RETURN(1);
DBUG_RETURN((int) mysql_read_query_result(mysql));
}
static my_bool
send_file_to_server(MYSQL *mysql, const char *filename)
{
int fd, readcount;
my_bool result= 1;
uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE);
char *buf, tmp_name[FN_REFLEN];
DBUG_ENTER("send_file_to_server");
if (!(buf=my_malloc(packet_length,MYF(0))))
{
strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY));
DBUG_RETURN(1);
}
fn_format(tmp_name,filename,"","",4); /* Convert to client format */
if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0)
{
my_net_write(&mysql->net,"",0); /* Server needs one packet */
net_flush(&mysql->net);
mysql->net.last_errno=EE_FILENOTFOUND;
my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1,
EE(mysql->net.last_errno),tmp_name, errno);
goto err;
}
while ((readcount = (int) my_read(fd,(byte*) buf,packet_length,MYF(0))) > 0)
{
if (my_net_write(&mysql->net,buf,readcount))
{
DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file"));
mysql->net.last_errno=CR_SERVER_LOST;
strmov(mysql->net.last_error,ER(mysql->net.last_errno));
goto err;
}
}
/* Send empty packet to mark end of file */
if (my_net_write(&mysql->net,"",0) || net_flush(&mysql->net))
{
mysql->net.last_errno=CR_SERVER_LOST;
sprintf(mysql->net.last_error,ER(mysql->net.last_errno),errno);
goto err;
}
if (readcount < 0)
{
mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */
my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1,
tmp_name,errno);
goto err;
}
result=0; /* Ok */
err:
if (fd >= 0)
(void) my_close(fd,MYF(0));
my_free(buf,MYF(0));
DBUG_RETURN(result);
}
/**************************************************************************
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");
#ifdef _libmysql_c
/* read from the actually used connection */
mysql = mysql->last_used_con;
#endif
if (!mysql->fields)
DBUG_RETURN(0);
if (mysql->status != MYSQL_STATUS_GET_RESULT)
{
strmov(mysql->net.last_error,
ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
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))))
{
mysql->net.last_errno=CR_OUT_OF_MEMORY;
strmov(mysql->net.last_error, ER(mysql->net.last_errno));
DBUG_RETURN(0);
}
result->eof=1; /* Marker for buffered */
result->lengths=(ulong*) (result+1);
if (!(result->data=read_rows(mysql,mysql->fields,mysql->field_count)))
{
my_free((gptr) 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;
result->current_field=0;
result->current_row=0; /* Must do a fetch first */
mysql->fields=0; /* fields is now in result */
DBUG_RETURN(result); /* Data 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)
{
if (!(read_one_row(res->handle,res->field_count,res->row, res->lengths)))
{
res->row_count++;
DBUG_RETURN(res->current_row=res->row);
}
else
{
DBUG_PRINT("info",("end of data"));
res->eof=1;
res->handle->status=MYSQL_STATUS_READY;
/* Don't clear handle in mysql_free_results */
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);
}
}
/**************************************************************************
Move to a specific row and column
**************************************************************************/
void STDCALL
mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
{
MYSQL_ROWS *tmp=0;
DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
if (result->data)
for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
result->current_row=0;
result->data_cursor = tmp;
}
/****************************************************************************
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->net.last_errno;
}
const char * STDCALL mysql_error(MYSQL *mysql)
{
return mysql->net.last_error;
}
...@@ -76,18 +76,6 @@ extern "C" { // Because of SCO 3.2V4.2 ...@@ -76,18 +76,6 @@ extern "C" { // Because of SCO 3.2V4.2
#endif #endif
} }
static void mc_free_rows(MYSQL_DATA *cur);
void mc_end_server(MYSQL *mysql);
static int mc_sock_connect(File s, const struct sockaddr *name, uint namelen, uint to);
static void mc_free_old_query(MYSQL *mysql);
static int mc_send_file_to_server(MYSQL *mysql, const char *filename);
static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
ulong *lengths);
static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
uint fields);
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | \ #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | \
CLIENT_LOCAL_FILES | CLIENT_SECURE_CONNECTION) CLIENT_LOCAL_FILES | CLIENT_SECURE_CONNECTION)
...@@ -99,1324 +87,13 @@ static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, ...@@ -99,1324 +87,13 @@ static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
#define SOCKET_ERROR -1 #define SOCKET_ERROR -1
#endif #endif
#ifdef __WIN__
static my_bool is_NT(void)
{
char *os=getenv("OS");
return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
}
#endif
extern ulong slave_net_timeout; extern ulong slave_net_timeout;
#define _mini_client_c
#define init_sigpipe_variables
#define set_sigpipe(mysql)
#define reset_sigpipe(mysql)
#include "../sql-common/client.c"
/* #endif /* HAVE_EXTERNAL_CLIENT */
** Create a named pipe connection
*/
#ifdef __WIN__
HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
char **arg_unix_socket)
{
HANDLE hPipe=INVALID_HANDLE_VALUE;
char szPipeName [ 257 ];
DWORD dwMode;
int i;
my_bool testing_named_pipes=0;
char *host= *arg_host, *unix_socket= *arg_unix_socket;
if (!host || !strcmp(host,LOCAL_HOST))
host=LOCAL_HOST_NAMEDPIPE;
sprintf(szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
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(szPipeName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL )) != INVALID_HANDLE_VALUE)
break;
if (GetLastError() != ERROR_PIPE_BUSY)
{
net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
(ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
/* wait for for an other instance */
if (! WaitNamedPipe(szPipeName, connect_timeout*1000) )
{
net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
(ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
}
if (hPipe == INVALID_HANDLE_VALUE)
{
net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
(ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
{
CloseHandle( hPipe );
net->last_errno=CR_NAMEDPIPESETSTATE_ERROR;
sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
(ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
*arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
return (hPipe);
}
#endif
/****************************************************************************
** Init MySQL structure or allocate one
****************************************************************************/
MYSQL *mc_mysql_init(MYSQL *mysql)
{
init_client_errs();
if (!mysql)
{
if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
return 0;
mysql->free_me=1;
mysql->net.vio = 0;
}
else
bzero((char*) (mysql),sizeof(*(mysql)));
#ifdef __WIN__
mysql->options.connect_timeout=20;
#endif
mysql->net.read_timeout = slave_net_timeout;
return mysql;
}
/**************************************************************************
** Shut down connection
**************************************************************************/
void
mc_end_server(MYSQL *mysql)
{
DBUG_ENTER("mc_end_server");
if (mysql->net.vio != 0)
{
DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio)));
vio_delete(mysql->net.vio);
mysql->net.vio= 0; /* Marker */
}
net_end(&mysql->net);
mc_free_old_query(mysql);
DBUG_VOID_RETURN;
}
static void mc_free_old_query(MYSQL *mysql)
{
DBUG_ENTER("mc_free_old_query");
if (mysql->fields)
free_root(&mysql->field_alloc,MYF(0));
else
init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
mysql->fields=0;
mysql->field_count=0; /* For API */
DBUG_VOID_RETURN;
}
/****************************************************************************
* A modified version of connect(). mc_sock_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,
* mc_sock_connect() will behave exactly like connect().
*
* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
*****************************************************************************/
static int mc_sock_connect(my_socket s, const struct sockaddr *name,
uint namelen, uint to)
{
#if defined(__WIN__) || defined(OS2) || defined(__NETWARE__)
return connect(s, (struct sockaddr*) name, namelen);
#else
int flags, res, s_err;
SOCKOPT_OPTLEN_TYPE s_err_size = sizeof(uint);
fd_set sfds;
struct timeval tv;
/* If they passed us a timeout of zero, we should behave
* exactly like the normal connect() call does.
*/
if (to == 0)
return connect(s, (struct sockaddr*) name, namelen);
flags = fcntl(s, F_GETFL, 0); /* Set socket to not block */
#ifdef O_NONBLOCK
fcntl(s, F_SETFL, flags | O_NONBLOCK); /* and save the flags.. */
#endif
res = connect(s, (struct sockaddr*) name, namelen);
s_err = errno; /* Save the error... */
fcntl(s, F_SETFL, flags);
if ((res != 0) && (s_err != EINPROGRESS))
{
errno = s_err; /* Restore it */
return(-1);
}
if (res == 0) /* Connected quickly! */
return(0);
/* Otherwise, our connection is "in progress." We can use
* the select() call to wait up to a specified period of time
* for the connection to suceed. If select() returns 0
* (after waiting howevermany seconds), our socket never became
* writable (host is probably unreachable.) Otherwise, if
* select() returns 1, then one of two conditions exist:
*
* 1. An error occured. We use getsockopt() to check for this.
* 2. The connection was set up sucessfully: getsockopt() will
* return 0 as an error.
*
* Thanks goes to Andrew Gierth <andrew@erlenstar.demon.co.uk>
* who posted this method of timing out a connect() in
* comp.unix.programmer on August 15th, 1997.
*/
FD_ZERO(&sfds);
FD_SET(s, &sfds);
tv.tv_sec = (long) to;
tv.tv_usec = 0;
#ifdef HPUX10
res = select(s+1, NULL, (int*) &sfds, NULL, &tv);
#else
res = select(s+1, NULL, &sfds, NULL, &tv);
#endif /* HPUX10 */
if (res <= 0) /* Never became writable */
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(s, 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); /* It's all good! */
#endif
}
/*****************************************************************************
** read a packet from server. Give error message if socket was down
** or packet is an error message
*****************************************************************************/
ulong
mc_net_safe_read(MYSQL *mysql)
{
NET *net= &mysql->net;
ulong len=0;
if (net->vio != 0)
len=my_net_read(net);
if (len == packet_error || len == 0)
{
DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d",
vio_description(net->vio),len));
if (socket_errno != SOCKET_EINTR)
{
mc_end_server(mysql);
if (net->last_errno != ER_NET_PACKET_TOO_LARGE)
{
net->last_errno=CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
}
else
strmov(net->last_error, "Packet too large - increase \
max_allowed_packet on this server");
}
return(packet_error);
}
if (net->read_pos[0] == 255)
{
if (len > 3)
{
char *pos=(char*) net->read_pos+1;
if (mysql->protocol_version > 9)
{ /* New client protocol */
net->last_errno=uint2korr(pos);
pos+=2;
len-=2;
if (!net->last_errno)
net->last_errno = CR_UNKNOWN_ERROR;
}
else
{
net->last_errno=CR_UNKNOWN_ERROR;
len--;
}
(void) strmake(net->last_error,(char*) pos,
min(len,sizeof(net->last_error)-1));
}
else
{
net->last_errno=CR_UNKNOWN_ERROR;
(void) strmov(net->last_error,ER(net->last_errno));
}
DBUG_PRINT("error",("Got error: %d (%s)", net->last_errno,
net->last_error));
return(packet_error);
}
return len;
}
char *mc_mysql_error(MYSQL *mysql)
{
return (mysql)->net.last_error;
}
int mc_mysql_errno(MYSQL *mysql)
{
return (mysql)->net.last_errno;
}
my_bool mc_mysql_reconnect(MYSQL *mysql)
{
MYSQL tmp_mysql;
DBUG_ENTER("mc_mysql_reconnect");
if (!mysql->reconnect)
{
mysql->net.last_errno=CR_SERVER_GONE_ERROR;
strmov(mysql->net.last_error, ER(mysql->net.last_errno));
DBUG_RETURN(1);
}
mc_mysql_init(&tmp_mysql);
tmp_mysql.options=mysql->options;
if (!mc_mysql_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
mysql->db, mysql->port, mysql->unix_socket,
mysql->client_flag, mysql->net.read_timeout))
{
mysql->net.last_errno= tmp_mysql.net.last_errno;
strmov(mysql->net.last_error, tmp_mysql.net.last_error);
DBUG_RETURN(1);
}
tmp_mysql.free_me=mysql->free_me;
mysql->free_me=0;
bzero((char*) &mysql->options,sizeof(&mysql->options));
mc_mysql_close(mysql);
*mysql=tmp_mysql;
net_clear(&mysql->net);
mysql->affected_rows= ~(my_ulonglong) 0;
DBUG_RETURN(0);
}
int
mc_simple_command(MYSQL *mysql,enum enum_server_command command,
const char *arg, uint length, my_bool skipp_check)
{
NET *net= &mysql->net;
int result= -1;
if (mysql->net.vio == 0)
{ /* Do reconnect if possible */
if (mc_mysql_reconnect(mysql))
goto end;
}
if (mysql->status != MYSQL_STATUS_READY)
{
strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
goto end;
}
mysql->net.last_error[0]=0;
mysql->net.last_errno=0;
mysql->net.report_error=0;
mysql->info=0;
mysql->affected_rows= ~(my_ulonglong) 0;
net_clear(net); /* Clear receive buffer */
if (!arg)
arg="";
if (net_write_command(net, (uchar) command, NullS, 0, arg, length))
{
DBUG_PRINT("error",("Can't send command to server. Error: %d",
socket_errno));
mc_end_server(mysql);
if (mc_mysql_reconnect(mysql))
goto end;
if (net_write_command(net,(uchar) command, NullS, 0, arg, length))
{
net->last_errno=CR_SERVER_GONE_ERROR;
strmov(net->last_error,ER(net->last_errno));
goto end;
}
}
result=0;
if (!skipp_check)
result= ((mysql->packet_length=mc_net_safe_read(mysql)) == packet_error ?
-1 : 0);
end:
return result;
}
MYSQL *
mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag,
uint net_read_timeout)
{
char buff[NAME_LEN+USERNAME_LENGTH+100],*end,*host_info;
char password_hash[SCRAMBLE41_LENGTH];
my_socket sock;
ulong ip_addr;
struct sockaddr_in sock_addr;
ulong pkt_length;
NET *net= &mysql->net;
thr_alarm_t alarmed;
ALARM alarm_buff;
ulong max_allowed_packet;
#ifdef __WIN__
HANDLE hPipe=INVALID_HANDLE_VALUE;
#endif
#ifdef HAVE_SYS_UN_H
struct sockaddr_un UNIXaddr;
#endif
DBUG_ENTER("mc_mysql_connect");
DBUG_PRINT("enter",("host: %s db: %s user: %s connect_time_out: %u read_timeout: %u",
host ? host : "(Null)",
db ? db : "(Null)",
user ? user : "(Null)",
net_read_timeout,
(uint) slave_net_timeout));
net->vio = 0; /* If something goes wrong */
mysql->charset=default_charset_info; /* Set character set */
if (!port)
port = MYSQL_PORT; /* Should always be set by mysqld */
if (!unix_socket)
unix_socket=MYSQL_UNIX_ADDR;
mysql->reconnect=1; /* Reconnect as default */
mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
if (!mysql->options.connect_timeout)
mysql->options.connect_timeout= net_read_timeout;
/*
** Grab a socket and connect it to the server
*/
#if defined(HAVE_SYS_UN_H)
if ((!host || !strcmp(host,LOCAL_HOST)) && unix_socket)
{
host=LOCAL_HOST;
host_info=(char*) ER(CR_LOCALHOST_CONNECTION);
DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
{
net->last_errno=CR_SOCKET_CREATE_ERROR;
sprintf(net->last_error,ER(net->last_errno),socket_errno);
goto error;
}
net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
UNIXaddr.sun_family = AF_UNIX;
strmov(UNIXaddr.sun_path, unix_socket);
if (mc_sock_connect(sock,
my_reinterpret_cast(struct sockaddr *) (&UNIXaddr),
sizeof(UNIXaddr),
mysql->options.connect_timeout) <0)
{
DBUG_PRINT("error",("Got error %d on connect to local server",
socket_errno));
net->last_errno=CR_CONNECTION_ERROR;
sprintf(net->last_error,ER(net->last_errno),unix_socket,socket_errno);
goto error;
}
}
else
#elif defined(__WIN__)
{
if ((unix_socket ||
!host && is_NT() ||
host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||
mysql->options.named_pipe || !have_tcpip))
{
sock=0;
if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
(char**) &host, (char**) &unix_socket)) ==
INVALID_HANDLE_VALUE)
{
DBUG_PRINT("error",
("host: '%s' socket: '%s' named_pipe: %d have_tcpip: %d",
host ? host : "<null>",
unix_socket ? unix_socket : "<null>",
(int) mysql->options.named_pipe,
(int) have_tcpip));
if (mysql->options.named_pipe ||
(host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
(unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
goto error; /* User only requested named pipes */
/* Try also with TCP/IP */
}
else
{
net->vio=vio_new_win32pipe(hPipe);
sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host,
unix_socket);
}
}
}
if (hPipe == INVALID_HANDLE_VALUE)
#endif
{
unix_socket=0; /* This is not used */
if (!host)
host=LOCAL_HOST;
sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
thr_alarm_init(&alarmed);
thr_alarm(&alarmed, net_read_timeout, &alarm_buff);
sock = (my_socket) socket(AF_INET,SOCK_STREAM,0);
thr_end_alarm(&alarmed);
if (sock == SOCKET_ERROR)
{
net->last_errno=CR_IPSOCK_ERROR;
sprintf(net->last_error,ER(net->last_errno),socket_errno);
goto error;
}
net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
bzero((char*) &sock_addr,sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
/*
** The server name may be a host name or IP address
*/
if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE)
{
memcpy_fixed(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr));
}
else
{
int tmp_errno;
struct hostent tmp_hostent,*hp;
char buff2[GETHOSTBYNAME_BUFF_SIZE];
hp = my_gethostbyname_r(host,&tmp_hostent,buff2,sizeof(buff2),
&tmp_errno);
if (!hp)
{
net->last_errno=CR_UNKNOWN_HOST;
sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, tmp_errno);
my_gethostbyname_r_free();
goto error;
}
memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
my_gethostbyname_r_free();
}
sock_addr.sin_port = (ushort) htons((ushort) port);
if (mc_sock_connect(sock,
my_reinterpret_cast(struct sockaddr *) (&sock_addr),
sizeof(sock_addr),
mysql->options.connect_timeout) <0)
{
DBUG_PRINT("error",("Got error %d on connect to '%s'",
socket_errno,host));
net->last_errno= CR_CONN_HOST_ERROR;
sprintf(net->last_error ,ER(CR_CONN_HOST_ERROR), host, socket_errno);
goto error;
}
}
if (!net->vio || my_net_init(net, net->vio))
{
vio_delete(net->vio);
net->vio = 0;
net->last_errno=CR_OUT_OF_MEMORY;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
vio_keepalive(net->vio,TRUE);
net->read_timeout=slave_net_timeout;
/* Get version info */
mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
if (mysql->options.connect_timeout &&
vio_poll_read(net->vio, mysql->options.connect_timeout))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
if ((pkt_length=mc_net_safe_read(mysql)) == packet_error)
goto error;
/* Check if version of protocol matches current one */
mysql->protocol_version= net->read_pos[0];
DBUG_DUMP("packet",(char*) net->read_pos,10);
DBUG_PRINT("info",("mysql protocol version %d, server=%d",
PROTOCOL_VERSION, mysql->protocol_version));
if (mysql->protocol_version != PROTOCOL_VERSION &&
mysql->protocol_version != PROTOCOL_VERSION-1)
{
net->last_errno= CR_VERSION_ERROR;
sprintf(net->last_error, 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;
strmake(mysql->scramble_buff,end,8);
end+=9;
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);
}
/* Save connection information */
if (!user) user="";
if (!passwd) passwd="";
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))))
{
strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY));
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;
client_flag|=mysql->options.client_flag;
DBUG_PRINT("info",("Server version = '%s' capabilites: %ld",
mysql->server_version,mysql->server_capabilities));
/* Send client information for access check */
client_flag|=CLIENT_CAPABILITIES;
#ifdef HAVE_OPENSSL
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 */
if (db)
client_flag|=CLIENT_CONNECT_WITH_DB;
#ifdef HAVE_COMPRESS
if ((mysql->server_capabilities & CLIENT_COMPRESS) &&
(mysql->options.compress || (client_flag & CLIENT_COMPRESS)))
client_flag|=CLIENT_COMPRESS; /* We will use compression */
else
#endif
client_flag&= ~CLIENT_COMPRESS;
#ifdef HAVE_OPENSSL
if ((mysql->server_capabilities & CLIENT_SSL) &&
(mysql->options.use_ssl || (client_flag & CLIENT_SSL)))
{
DBUG_PRINT("info", ("Changing IO layer to SSL"));
client_flag |= CLIENT_SSL;
}
else
{
if (client_flag & CLIENT_SSL)
{
DBUG_PRINT("info", ("Leaving IO layer intact because server doesn't support SSL"));
}
client_flag &= ~CLIENT_SSL;
}
#endif /* HAVE_OPENSSL */
int2store(buff,client_flag);
mysql->client_flag=client_flag;
#ifdef HAVE_OPENSSL
/*
Oops.. are we careful enough to not send ANY information without
encryption?
*/
if (client_flag & CLIENT_SSL)
{
if (my_net_write(net,buff,(uint) (2)) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Do the SSL layering. */
DBUG_PRINT("info", ("IO layer change in progress..."));
DBUG_PRINT("info", ("IO context %p",((struct st_VioSSLConnectorFd*)mysql->connector_fd)->ssl_context_));
sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd),mysql->net.vio, (long)(mysql->options.connect_timeout));
DBUG_PRINT("info", ("IO layer change done!"));
}
#endif /* HAVE_OPENSSL */
max_allowed_packet=mysql->net.max_packet_size;
int3store(buff+2,max_allowed_packet);
if (user && user[0])
strmake(buff+5,user,32);
else
{
user = getenv("USER");
if (!user) user = "mysql";
strmov((char*) buff+5, user );
}
DBUG_PRINT("info",("user: %s",buff+5));
/*
We always start with old type handshake the only difference is message sent
If server handles secure connection type we'll not send the real scramble
*/
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
if (passwd[0])
{
/* Prepare false scramble */
end=strend(buff+5)+1;
bfill(end, SCRAMBLE_LENGTH, 'x');
end+=SCRAMBLE_LENGTH;
*end=0;
}
else /* For empty password*/
{
end=strend(buff+5)+1;
*end=0; /* Store zero length scramble */
}
}
else
{
/*
Real scramble is only sent to old servers. This can be blocked
by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1);
*/
end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
}
/* Add database if needed */
if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
{
end=strmake(end+1,db,NAME_LEN);
mysql->db=my_strdup(db,MYF(MY_WME));
db=0;
}
/* Write authentication package */
if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* We shall only query sever if it expect us to do so */
if ( (pkt_length=mc_net_safe_read(mysql)) == packet_error)
goto error;
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
/* This should always happen with new server unless empty password */
if (pkt_length==24 && net->read_pos[0])
/* OK/Error message has zero as the first character */
{
/* Old passwords will have zero at the first byte of hash */
if (net->read_pos[0] != '*')
{
/* Build full password hash as it is required to decode scramble */
password_hash_stage1(buff, passwd);
/* Store copy as we'll need it later */
memcpy(password_hash,buff,SCRAMBLE41_LENGTH);
/* Finally hash complete password using hash we got from server */
password_hash_stage2(password_hash,(char*)net->read_pos);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((char*)net->read_pos+4,mysql->scramble_buff,password_hash,
SCRAMBLE41_LENGTH);
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
/* Encode scramble with password. Recycle buffer */
password_crypt(mysql->scramble_buff,buff,buff,SCRAMBLE41_LENGTH);
}
else
{
/* Create password to decode scramble */
create_key_from_old_password(passwd,password_hash);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((char*)net->read_pos+4,mysql->scramble_buff,password_hash,
SCRAMBLE41_LENGTH);
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
/* Finally scramble decoded scramble with password */
scramble(buff, mysql->scramble_buff, passwd,0);
}
/* Write second package of authentication */
if (my_net_write(net,buff,SCRAMBLE41_LENGTH) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Read What server thinks about out new auth message report */
if (mc_net_safe_read(mysql) == packet_error)
goto error;
}
}
/* End of authentication part of handshake */
if (client_flag & CLIENT_COMPRESS) /* We will use compression */
net->compress=1;
DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
DBUG_RETURN(mysql);
error:
DBUG_PRINT("error",("message: %u (%s)",net->last_errno,net->last_error));
{
/* Free alloced memory */
my_bool free_me=mysql->free_me;
mc_end_server(mysql);
mysql->free_me=0;
mc_mysql_close(mysql);
mysql->free_me=free_me;
}
DBUG_RETURN(0);
}
#ifdef HAVE_OPENSSL
/*
**************************************************************************
** Free strings in the SSL structure and clear 'use_ssl' flag.
** NB! Errors are not reported until you do mysql_real_connect.
**************************************************************************
*/
int
mysql_ssl_clear(MYSQL *mysql)
{
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));
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;
my_free(mysql->connector_fd,MYF(MY_ALLOW_ZERO_PTR));
mysql->connector_fd = 0;
return 0;
}
#endif /* HAVE_OPENSSL */
/*************************************************************************
** Send a QUIT to the server and close the connection
** If handle is alloced by mysql connect free it.
*************************************************************************/
void
mc_mysql_close(MYSQL *mysql)
{
DBUG_ENTER("mysql_close");
if (mysql) /* Some simple safety */
{
if (mysql->net.vio != 0)
{
mc_free_old_query(mysql);
mysql->status=MYSQL_STATUS_READY; /* Force command */
mysql->reconnect=0;
mc_simple_command(mysql,COM_QUIT,NullS,0,1);
mc_end_server(mysql);
}
my_free((gptr) 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));
/* Clear pointers for better safety */
mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
bzero((char*) &mysql->options,sizeof(mysql->options));
#ifdef HAVE_OPENSSL
mysql_ssl_clear(mysql);
#endif /* HAVE_OPENSSL */
if (mysql->free_me)
my_free((gptr) mysql,MYF(0));
}
DBUG_VOID_RETURN;
}
void mc_mysql_free_result(MYSQL_RES *result)
{
DBUG_ENTER("mc_mysql_free_result");
DBUG_PRINT("enter",("mysql_res: %lx",result));
if (result)
{
if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
{
DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows"));
for (;;)
{
ulong pkt_len;
if ((pkt_len=mc_net_safe_read(result->handle)) == packet_error)
break;
if (pkt_len == 1 && result->handle->net.read_pos[0] == 254)
break; /* End of data */
}
result->handle->status=MYSQL_STATUS_READY;
}
mc_free_rows(result->data);
if (result->fields)
free_root(&result->field_alloc,MYF(0));
if (result->row)
my_free((gptr) result->row,MYF(0));
my_free((gptr) result,MYF(0));
}
DBUG_VOID_RETURN;
}
static void mc_free_rows(MYSQL_DATA *cur)
{
if (cur)
{
free_root(&cur->alloc,MYF(0));
my_free((gptr) cur,MYF(0));
}
}
static MYSQL_FIELD *
mc_unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
my_bool default_value, my_bool long_flag_protocol)
{
MYSQL_ROWS *row;
MYSQL_FIELD *field,*result;
DBUG_ENTER("unpack_fields");
field=result=(MYSQL_FIELD*) alloc_root(alloc,sizeof(MYSQL_FIELD)*fields);
if (!result)
DBUG_RETURN(0);
for (row=data->data; row ; row = row->next,field++)
{
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];
if (long_flag_protocol)
{
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]);
else
field->def=0;
field->max_length= 0;
}
mc_free_rows(data); /* Free old data */
DBUG_RETURN(result);
}
int mc_mysql_send_query(MYSQL* mysql, const char* query, uint length)
{
return mc_simple_command(mysql, COM_QUERY, query, length, 1);
}
int mc_mysql_read_query_result(MYSQL *mysql)
{
uchar *pos;
ulong field_count;
MYSQL_DATA *fields;
ulong length;
DBUG_ENTER("mc_mysql_read_query_result");
if ((length = mc_net_safe_read(mysql)) == packet_error)
DBUG_RETURN(-1);
mc_free_old_query(mysql); /* Free old result */
get_info:
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);
if (mysql->server_capabilities & CLIENT_TRANSACTIONS)
{
mysql->server_status=uint2korr(pos); pos+=2;
}
if (pos < mysql->net.read_pos+length && net_field_length(&pos))
mysql->info=(char*) pos;
DBUG_RETURN(0);
}
if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
{
int error=mc_send_file_to_server(mysql,(char*) pos);
if ((length=mc_net_safe_read(mysql)) == packet_error || error)
DBUG_RETURN(-1);
goto get_info; /* Get info packet */
}
if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
mysql->server_status|= SERVER_STATUS_IN_TRANS;
mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
if (!(fields=mc_read_rows(mysql,(MYSQL_FIELD*) 0,5)))
DBUG_RETURN(-1);
if (!(mysql->fields=mc_unpack_fields(fields,&mysql->field_alloc,
(uint) field_count,0,
(my_bool) test(mysql->server_capabilities &
CLIENT_LONG_FLAG))))
DBUG_RETURN(-1);
mysql->status=MYSQL_STATUS_GET_RESULT;
mysql->field_count=field_count;
DBUG_RETURN(0);
}
int mc_mysql_query(MYSQL *mysql, const char *query, uint length)
{
DBUG_ENTER("mc_mysql_query");
DBUG_PRINT("enter",("handle: %lx",mysql));
DBUG_PRINT("query",("Query = \"%s\"",query));
DBUG_ASSERT(length == strlen(query));
if (mc_simple_command(mysql,COM_QUERY,query,length,1))
DBUG_RETURN(-1);
DBUG_RETURN(mc_mysql_read_query_result(mysql));
}
static int mc_send_file_to_server(MYSQL *mysql, const char *filename)
{
int fd, readcount, result= -1;
uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE);
char *buf, tmp_name[FN_REFLEN];
DBUG_ENTER("send_file_to_server");
if (!(buf=my_malloc(packet_length,MYF(0))))
{
strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY));
DBUG_RETURN(-1);
}
fn_format(tmp_name,filename,"","",4); /* Convert to client format */
if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0)
{
my_net_write(&mysql->net,"",0); // Server needs one packet
net_flush(&mysql->net);
mysql->net.last_errno=EE_FILENOTFOUND;
my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1,
EE(mysql->net.last_errno),tmp_name, errno);
goto err;
}
while ((readcount = (int) my_read(fd,(byte*) buf,packet_length,MYF(0))) > 0)
{
if (my_net_write(&mysql->net,buf,readcount))
{
DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file"));
mysql->net.last_errno=CR_SERVER_LOST;
strmov(mysql->net.last_error,ER(mysql->net.last_errno));
goto err;
}
}
/* Send empty packet to mark end of file */
if (my_net_write(&mysql->net,"",0) || net_flush(&mysql->net))
{
mysql->net.last_errno=CR_SERVER_LOST;
sprintf(mysql->net.last_error,ER(mysql->net.last_errno),errno);
goto err;
}
if (readcount < 0)
{
mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */
my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1,
tmp_name,errno);
goto err;
}
result=0; // Ok
err:
if (fd >= 0)
(void) my_close(fd,MYF(0));
my_free(buf,MYF(0));
DBUG_RETURN(result);
}
/* Read all rows (fields or data) from server */
static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
uint fields)
{
uint field;
ulong pkt_len;
ulong len;
uchar *cp;
char *to;
MYSQL_DATA *result;
MYSQL_ROWS **prev_ptr,*cur;
NET *net = &mysql->net;
DBUG_ENTER("mc_read_rows");
if ((pkt_len=mc_net_safe_read(mysql)) == packet_error)
DBUG_RETURN(0);
if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
MYF(MY_ZEROFILL))))
{
net->last_errno=CR_OUT_OF_MEMORY;
strmov(net->last_error,ER(net->last_errno));
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;
while (*(cp=net->read_pos) != 254 || pkt_len != 1)
{
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))))
{
mc_free_rows(result);
net->last_errno=CR_OUT_OF_MEMORY;
strmov(net->last_error,ER(net->last_errno));
DBUG_RETURN(0);
}
*prev_ptr=cur;
prev_ptr= &cur->next;
to= (char*) (cur->data+fields+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;
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=mc_net_safe_read(mysql)) == packet_error)
{
mc_free_rows(result);
DBUG_RETURN(0);
}
}
*prev_ptr=0; /* last pointer is null */
DBUG_PRINT("exit",("Got %d rows",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 mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
ulong *lengths)
{
uint field;
ulong pkt_len,len;
uchar *pos;
uchar *prev_pos;
if ((pkt_len=mc_net_safe_read(mysql)) == packet_error)
return -1;
if (pkt_len == 1 && mysql->net.read_pos[0] == 254)
return 1; /* End of data */
prev_pos= 0; /* allowed to write at packet[-1] */
pos=mysql->net.read_pos;
for (field=0 ; field < fields ; field++)
{
if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH)
{ /* null field */
row[field] = 0;
*lengths++=0;
}
else
{
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;
}
my_ulonglong mc_mysql_num_rows(MYSQL_RES *res)
{
return res->row_count;
}
unsigned int mc_mysql_num_fields(MYSQL_RES *res)
{
return res->field_count;
}
void mc_mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
{
MYSQL_ROWS *tmp=0;
DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
if (result->data)
for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
result->current_row=0;
result->data_cursor = tmp;
}
MYSQL_ROW STDCALL mc_mysql_fetch_row(MYSQL_RES *res)
{
DBUG_ENTER("mc_mysql_fetch_row");
if (!res->data)
{ /* Unbufferred fetch */
if (!res->eof)
{
if (!(mc_read_one_row(res->handle,res->field_count,res->row,
res->lengths)))
{
res->row_count++;
DBUG_RETURN(res->current_row=res->row);
}
else
{
DBUG_PRINT("info",("end of data"));
res->eof=1;
res->handle->status=MYSQL_STATUS_READY;
}
}
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);
}
}
int mc_mysql_select_db(MYSQL *mysql, const char *db)
{
int error;
DBUG_ENTER("mysql_select_db");
DBUG_PRINT("enter",("db: '%s'",db));
if ((error=mc_simple_command(mysql,COM_INIT_DB,db,(uint) 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);
}
MYSQL_RES *mc_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)
{
strmov(mysql->net.last_error,
ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
DBUG_RETURN(0);
}
mysql->status=MYSQL_STATUS_READY; /* server is ready */
if (!(result=(MYSQL_RES*) my_malloc(sizeof(MYSQL_RES)+
sizeof(ulong)*mysql->field_count,
MYF(MY_ZEROFILL))))
{
mysql->net.last_errno=CR_OUT_OF_MEMORY;
strmov(mysql->net.last_error, ER(mysql->net.last_errno));
DBUG_RETURN(0);
}
result->eof=1; /* Marker for buffered */
result->lengths=(ulong*) (result+1);
if (!(result->data=mc_read_rows(mysql,mysql->fields,mysql->field_count)))
{
my_free((gptr) 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;
result->current_field=0;
result->current_row=0; /* Must do a fetch first */
mysql->fields=0; /* fields is now in result */
DBUG_RETURN(result); /* Data fetched */
}
#endif /* HAVE_EXTERNAL_CLIENT */
...@@ -17,30 +17,32 @@ ...@@ -17,30 +17,32 @@
#ifndef _MINI_CLIENT_H #ifndef _MINI_CLIENT_H
#define _MINI_CLIENT_H #define _MINI_CLIENT_H
MYSQL *
MYSQL* mc_mysql_connect(MYSQL *mysql,const char *host, const char *user, mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db, const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag, uint port, const char *unix_socket,ulong client_flag,
uint net_read_timeout); uint net_read_timeout);
int mc_simple_command(MYSQL *mysql,enum enum_server_command command,
const char *arg, uint length, my_bool skipp_check); my_bool simple_command(MYSQL *mysql,enum enum_server_command command,
void mc_mysql_close(MYSQL *mysql); const char *arg, unsigned long length,
MYSQL *mc_mysql_init(MYSQL *mysql); my_bool skip_check);
void mc_mysql_debug(const char *debug); void mysql_close(MYSQL *mysql);
ulong mc_net_safe_read(MYSQL *mysql); MYSQL *mysql_init(MYSQL *mysql);
char *mc_mysql_error(MYSQL *mysql); void mysql_debug(const char *debug);
int mc_mysql_errno(MYSQL *mysql); ulong net_safe_read(MYSQL *mysql);
my_bool mc_mysql_reconnect(MYSQL* mysql); const char *mysql_error(MYSQL *mysql);
int mc_mysql_send_query(MYSQL* mysql, const char* query, uint length); unsigned int mysql_errno(MYSQL *mysql);
int mc_mysql_read_query_result(MYSQL *mysql); my_bool mysql_reconnect(MYSQL* mysql);
int mc_mysql_query(MYSQL *mysql, const char *query, uint length); int mysql_send_query(MYSQL* mysql, const char* query, uint length);
MYSQL_RES * mc_mysql_store_result(MYSQL *mysql); my_bool mysql_read_query_result(MYSQL *mysql);
void mc_mysql_free_result(MYSQL_RES *result); int mysql_real_query(MYSQL *mysql, const char *q, unsigned long length);
void mc_mysql_data_seek(MYSQL_RES *result, my_ulonglong row); MYSQL_RES * mysql_store_result(MYSQL *mysql);
my_ulonglong mc_mysql_num_rows(MYSQL_RES *res); void mysql_free_result(MYSQL_RES *result);
unsigned int mc_mysql_num_fields(MYSQL_RES *res); void mysql_data_seek(MYSQL_RES *result, my_ulonglong row);
MYSQL_ROW STDCALL mc_mysql_fetch_row(MYSQL_RES *res); my_ulonglong mysql_num_rows(MYSQL_RES *res);
int mc_mysql_select_db(MYSQL *mysql, const char *db); unsigned int mysql_num_fields(MYSQL_RES *res);
void mc_end_server(MYSQL *mysql); MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *res);
int mysql_select_db(MYSQL *mysql, const char *db);
void end_server(MYSQL *mysql);
#endif #endif
...@@ -484,14 +484,15 @@ int update_slave_list(MYSQL* mysql, MASTER_INFO* mi) ...@@ -484,14 +484,15 @@ int update_slave_list(MYSQL* mysql, MASTER_INFO* mi)
int port_ind; int port_ind;
DBUG_ENTER("update_slave_list"); DBUG_ENTER("update_slave_list");
if (mc_mysql_query(mysql,"SHOW SLAVE HOSTS",16) ||
!(res = mc_mysql_store_result(mysql))) if (mysql_real_query(mysql,"SHOW SLAVE HOSTS",16) ||
!(res = mysql_store_result(mysql)))
{ {
error= mc_mysql_error(mysql); error= mysql_error(mysql);
goto err; goto err;
} }
switch (mc_mysql_num_fields(res)) { switch (mysql_num_fields(res)) {
case 5: case 5:
have_auth_info = 0; have_auth_info = 0;
port_ind=2; port_ind=2;
...@@ -508,7 +509,7 @@ HOSTS"; ...@@ -508,7 +509,7 @@ HOSTS";
pthread_mutex_lock(&LOCK_slave_list); pthread_mutex_lock(&LOCK_slave_list);
while ((row= mc_mysql_fetch_row(res))) while ((row= mysql_fetch_row(res)))
{ {
uint32 server_id; uint32 server_id;
SLAVE_INFO* si, *old_si; SLAVE_INFO* si, *old_si;
...@@ -541,7 +542,7 @@ HOSTS"; ...@@ -541,7 +542,7 @@ HOSTS";
err: err:
if (res) if (res)
mc_mysql_free_result(res); mysql_free_result(res);
if (error) if (error)
{ {
sql_print_error("While trying to obtain the list of slaves from the master \ sql_print_error("While trying to obtain the list of slaves from the master \
...@@ -566,7 +567,7 @@ pthread_handler_decl(handle_failsafe_rpl,arg) ...@@ -566,7 +567,7 @@ pthread_handler_decl(handle_failsafe_rpl,arg)
thd->thread_stack = (char*)&thd; thd->thread_stack = (char*)&thd;
MYSQL* recovery_captain = 0; MYSQL* recovery_captain = 0;
pthread_detach_this_thread(); pthread_detach_this_thread();
if (init_failsafe_rpl_thread(thd) || !(recovery_captain=mc_mysql_init(0))) if (init_failsafe_rpl_thread(thd) || !(recovery_captain=mysql_init(0)))
{ {
sql_print_error("Could not initialize failsafe replication thread"); sql_print_error("Could not initialize failsafe replication thread");
goto err; goto err;
...@@ -599,7 +600,7 @@ pthread_handler_decl(handle_failsafe_rpl,arg) ...@@ -599,7 +600,7 @@ pthread_handler_decl(handle_failsafe_rpl,arg)
pthread_mutex_unlock(&LOCK_rpl_status); pthread_mutex_unlock(&LOCK_rpl_status);
err: err:
if (recovery_captain) if (recovery_captain)
mc_mysql_close(recovery_captain); mysql_close(recovery_captain);
delete thd; delete thd;
my_thread_end(); my_thread_end();
pthread_exit(0); pthread_exit(0);
...@@ -668,7 +669,7 @@ int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi) ...@@ -668,7 +669,7 @@ int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi)
strmov(mysql->net.last_error, "Master is not configured"); strmov(mysql->net.last_error, "Master is not configured");
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (!mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0, if (!mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0,
mi->port, 0, 0, mi->port, 0, 0,
slave_net_timeout)) slave_net_timeout))
DBUG_RETURN(1); DBUG_RETURN(1);
...@@ -682,9 +683,9 @@ static inline void cleanup_mysql_results(MYSQL_RES* db_res, ...@@ -682,9 +683,9 @@ static inline void cleanup_mysql_results(MYSQL_RES* db_res,
for (; cur >= start; --cur) for (; cur >= start; --cur)
{ {
if (*cur) if (*cur)
mc_mysql_free_result(*cur); mysql_free_result(*cur);
} }
mc_mysql_free_result(db_res); mysql_free_result(db_res);
} }
...@@ -692,8 +693,8 @@ static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db, ...@@ -692,8 +693,8 @@ static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db,
MYSQL_RES *table_res, MASTER_INFO *mi) MYSQL_RES *table_res, MASTER_INFO *mi)
{ {
MYSQL_ROW row; MYSQL_ROW row;
for (row = mc_mysql_fetch_row(table_res); row; for (row = mysql_fetch_row(table_res); row;
row = mc_mysql_fetch_row(table_res)) row = mysql_fetch_row(table_res))
{ {
TABLE_LIST table; TABLE_LIST table;
const char* table_name= row[0]; const char* table_name= row[0];
...@@ -727,7 +728,7 @@ int load_master_data(THD* thd) ...@@ -727,7 +728,7 @@ int load_master_data(THD* thd)
int error = 0; int error = 0;
const char* errmsg=0; const char* errmsg=0;
int restart_thread_mask; int restart_thread_mask;
mc_mysql_init(&mysql); mysql_init(&mysql);
/* /*
We do not want anyone messing with the slave at all for the entire We do not want anyone messing with the slave at all for the entire
...@@ -749,7 +750,7 @@ int load_master_data(THD* thd) ...@@ -749,7 +750,7 @@ int load_master_data(THD* thd)
if (connect_to_master(thd, &mysql, active_mi)) if (connect_to_master(thd, &mysql, active_mi))
{ {
net_printf(thd, error= ER_CONNECT_TO_MASTER, net_printf(thd, error= ER_CONNECT_TO_MASTER,
mc_mysql_error(&mysql)); mysql_error(&mysql));
goto err; goto err;
} }
...@@ -758,15 +759,15 @@ int load_master_data(THD* thd) ...@@ -758,15 +759,15 @@ int load_master_data(THD* thd)
MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res; MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res;
uint num_dbs; uint num_dbs;
if (mc_mysql_query(&mysql, "SHOW DATABASES", 14) || if (mysql_real_query(&mysql, "SHOW DATABASES", 14) ||
!(db_res = mc_mysql_store_result(&mysql))) !(db_res = mysql_store_result(&mysql)))
{ {
net_printf(thd, error = ER_QUERY_ON_MASTER, net_printf(thd, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql)); mysql_error(&mysql));
goto err; goto err;
} }
if (!(num_dbs = (uint) mc_mysql_num_rows(db_res))) if (!(num_dbs = (uint) mysql_num_rows(db_res)))
goto err; goto err;
/* /*
In theory, the master could have no databases at all In theory, the master could have no databases at all
...@@ -785,12 +786,12 @@ int load_master_data(THD* thd) ...@@ -785,12 +786,12 @@ int load_master_data(THD* thd)
we wait to issue FLUSH TABLES WITH READ LOCK for as long as we we wait to issue FLUSH TABLES WITH READ LOCK for as long as we
can to minimize the lock time. can to minimize the lock time.
*/ */
if (mc_mysql_query(&mysql, "FLUSH TABLES WITH READ LOCK", 27) || if (mysql_real_query(&mysql, "FLUSH TABLES WITH READ LOCK", 27) ||
mc_mysql_query(&mysql, "SHOW MASTER STATUS",18) || mysql_real_query(&mysql, "SHOW MASTER STATUS",18) ||
!(master_status_res = mc_mysql_store_result(&mysql))) !(master_status_res = mysql_store_result(&mysql)))
{ {
net_printf(thd, error = ER_QUERY_ON_MASTER, net_printf(thd, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql)); mysql_error(&mysql));
goto err; goto err;
} }
...@@ -805,7 +806,7 @@ int load_master_data(THD* thd) ...@@ -805,7 +806,7 @@ int load_master_data(THD* thd)
cur_table_res++) cur_table_res++)
{ {
// since we know how many rows we have, this can never be NULL // since we know how many rows we have, this can never be NULL
MYSQL_ROW row = mc_mysql_fetch_row(db_res); MYSQL_ROW row = mysql_fetch_row(db_res);
char* db = row[0]; char* db = row[0];
/* /*
...@@ -834,12 +835,12 @@ int load_master_data(THD* thd) ...@@ -834,12 +835,12 @@ int load_master_data(THD* thd)
goto err; goto err;
} }
if (mc_mysql_select_db(&mysql, db) || if (mysql_select_db(&mysql, db) ||
mc_mysql_query(&mysql, "SHOW TABLES", 11) || mysql_real_query(&mysql, "SHOW TABLES", 11) ||
!(*cur_table_res = mc_mysql_store_result(&mysql))) !(*cur_table_res = mysql_store_result(&mysql)))
{ {
net_printf(thd, error = ER_QUERY_ON_MASTER, net_printf(thd, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql)); mysql_error(&mysql));
cleanup_mysql_results(db_res, cur_table_res - 1, table_res); cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
goto err; goto err;
} }
...@@ -857,7 +858,7 @@ int load_master_data(THD* thd) ...@@ -857,7 +858,7 @@ int load_master_data(THD* thd)
// adjust position in the master // adjust position in the master
if (master_status_res) if (master_status_res)
{ {
MYSQL_ROW row = mc_mysql_fetch_row(master_status_res); MYSQL_ROW row = mysql_fetch_row(master_status_res);
/* /*
We need this check because the master may not be running with We need this check because the master may not be running with
...@@ -875,13 +876,13 @@ int load_master_data(THD* thd) ...@@ -875,13 +876,13 @@ int load_master_data(THD* thd)
active_mi->master_log_pos = BIN_LOG_HEADER_SIZE; active_mi->master_log_pos = BIN_LOG_HEADER_SIZE;
flush_master_info(active_mi); flush_master_info(active_mi);
} }
mc_mysql_free_result(master_status_res); mysql_free_result(master_status_res);
} }
if (mc_mysql_query(&mysql, "UNLOCK TABLES", 13)) if (mysql_real_query(&mysql, "UNLOCK TABLES", 13))
{ {
net_printf(thd, error = ER_QUERY_ON_MASTER, net_printf(thd, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql)); mysql_error(&mysql));
goto err; goto err;
} }
} }
...@@ -920,7 +921,7 @@ err: ...@@ -920,7 +921,7 @@ err:
UNLOCK_ACTIVE_MI; UNLOCK_ACTIVE_MI;
thd->proc_info = 0; thd->proc_info = 0;
mc_mysql_close(&mysql); // safe to call since we always do mc_mysql_init() mysql_close(&mysql); // safe to call since we always do mysql_init()
if (!error) if (!error)
send_ok(thd); send_ok(thd);
......
...@@ -1164,15 +1164,15 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name, ...@@ -1164,15 +1164,15 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
if (!called_connected) if (!called_connected)
{ {
if (!(mysql = mc_mysql_init(NULL))) if (!(mysql = mysql_init(NULL)))
{ {
send_error(thd); // EOM send_error(thd); // EOM
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (connect_to_master(thd, mysql, mi)) if (connect_to_master(thd, mysql, mi))
{ {
net_printf(thd, ER_CONNECT_TO_MASTER, mc_mysql_error(mysql)); net_printf(thd, ER_CONNECT_TO_MASTER, mysql_error(mysql));
mc_mysql_close(mysql); mysql_close(mysql);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (thd->killed) if (thd->killed)
...@@ -1193,7 +1193,7 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name, ...@@ -1193,7 +1193,7 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
err: err:
thd->net.no_send_ok = 0; // Clear up garbage after create_table_from_dump thd->net.no_send_ok = 0; // Clear up garbage after create_table_from_dump
if (!called_connected) if (!called_connected)
mc_mysql_close(mysql); mysql_close(mysql);
if (errmsg && thd->net.vio) if (errmsg && thd->net.vio)
send_error(thd, error, errmsg); send_error(thd, error, errmsg);
DBUG_RETURN(test(error)); // Return 1 on error DBUG_RETURN(test(error)); // Return 1 on error
...@@ -1560,12 +1560,12 @@ int register_slave_on_master(MYSQL* mysql) ...@@ -1560,12 +1560,12 @@ int register_slave_on_master(MYSQL* mysql)
/* The master will fill in master_id */ /* The master will fill in master_id */
int4store(pos, 0); pos+= 4; int4store(pos, 0); pos+= 4;
if (mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*) buf, if (simple_command(mysql, COM_REGISTER_SLAVE, (char*) buf,
(uint) (pos- buf), 0)) (uint) (pos- buf), 0))
{ {
sql_print_error("Error on COM_REGISTER_SLAVE: %d '%s'", sql_print_error("Error on COM_REGISTER_SLAVE: %d '%s'",
mc_mysql_errno(mysql), mysql_errno(mysql),
mc_mysql_error(mysql)); mysql_error(mysql));
return 1; return 1;
} }
return 0; return 0;
...@@ -1959,18 +1959,18 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi, ...@@ -1959,18 +1959,18 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi,
int4store(buf + 6, server_id); int4store(buf + 6, server_id);
len = (uint) strlen(logname); len = (uint) strlen(logname);
memcpy(buf + 10, logname,len); memcpy(buf + 10, logname,len);
if (mc_simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1)) if (simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1))
{ {
/* /*
Something went wrong, so we will just reconnect and retry later Something went wrong, so we will just reconnect and retry later
in the future, we should do a better error analysis, but for in the future, we should do a better error analysis, but for
now we just fill up the error log :-) now we just fill up the error log :-)
*/ */
if (mc_mysql_errno(mysql) == ER_NET_READ_INTERRUPTED) if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED)
*suppress_warnings= 1; // Suppress reconnect warning *suppress_warnings= 1; // Suppress reconnect warning
else else
sql_print_error("Error on COM_BINLOG_DUMP: %d %s, will retry in %d secs", sql_print_error("Error on COM_BINLOG_DUMP: %d %s, will retry in %d secs",
mc_mysql_errno(mysql), mc_mysql_error(mysql), mysql_errno(mysql), mysql_error(mysql),
master_connect_retry); master_connect_retry);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
...@@ -1997,7 +1997,7 @@ static int request_table_dump(MYSQL* mysql, const char* db, const char* table) ...@@ -1997,7 +1997,7 @@ static int request_table_dump(MYSQL* mysql, const char* db, const char* table)
*p++ = table_len; *p++ = table_len;
memcpy(p, table, table_len); memcpy(p, table, table_len);
if (mc_simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1)) if (simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1))
{ {
sql_print_error("request_table_dump: Error sending the table dump \ sql_print_error("request_table_dump: Error sending the table dump \
command"); command");
...@@ -2041,10 +2041,10 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings) ...@@ -2041,10 +2041,10 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
return packet_error; return packet_error;
#endif #endif
len = mc_net_safe_read(mysql); len = net_safe_read(mysql);
if (len == packet_error || (long) len < 1) if (len == packet_error || (long) len < 1)
{ {
if (mc_mysql_errno(mysql) == ER_NET_READ_INTERRUPTED) if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED)
{ {
/* /*
We are trying a normal reconnect after a read timeout; We are trying a normal reconnect after a read timeout;
...@@ -2056,7 +2056,7 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings) ...@@ -2056,7 +2056,7 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
else else
sql_print_error("Error reading packet from server: %s (\ sql_print_error("Error reading packet from server: %s (\
server_errno=%d)", server_errno=%d)",
mc_mysql_error(mysql), mc_mysql_errno(mysql)); mysql_error(mysql), mysql_errno(mysql));
return packet_error; return packet_error;
} }
...@@ -2064,7 +2064,7 @@ server_errno=%d)", ...@@ -2064,7 +2064,7 @@ server_errno=%d)",
{ {
sql_print_error("Slave: received 0 length packet from server, apparent\ sql_print_error("Slave: received 0 length packet from server, apparent\
master shutdown: %s", master shutdown: %s",
mc_mysql_error(mysql)); mysql_error(mysql));
return packet_error; return packet_error;
} }
...@@ -2214,7 +2214,7 @@ slave_begin: ...@@ -2214,7 +2214,7 @@ slave_begin:
mi->master_log_name, mi->master_log_name,
llstr(mi->master_log_pos,llbuff))); llstr(mi->master_log_pos,llbuff)));
if (!(mi->mysql = mysql = mc_mysql_init(NULL))) if (!(mi->mysql = mysql = mysql_init(NULL)))
{ {
sql_print_error("Slave I/O thread: error in mc_mysql_init()"); sql_print_error("Slave I/O thread: error in mc_mysql_init()");
goto err; goto err;
...@@ -2269,7 +2269,7 @@ dump"); ...@@ -2269,7 +2269,7 @@ dump");
} }
thd->proc_info = "Waiiting to reconnect after a failed dump request"; thd->proc_info = "Waiiting to reconnect after a failed dump request";
mc_end_server(mysql); end_server(mysql);
/* /*
First time retry immediately, assuming that we can recover First time retry immediately, assuming that we can recover
right away - if first time fails, sleep between re-tries right away - if first time fails, sleep between re-tries
...@@ -2319,7 +2319,7 @@ after reconnect"); ...@@ -2319,7 +2319,7 @@ after reconnect");
if (event_len == packet_error) if (event_len == packet_error)
{ {
uint mysql_error_number= mc_mysql_errno(mysql); uint mysql_error_number= mysql_errno(mysql);
if (mysql_error_number == ER_NET_PACKET_TOO_LARGE) if (mysql_error_number == ER_NET_PACKET_TOO_LARGE)
{ {
sql_print_error("\ sql_print_error("\
...@@ -2332,11 +2332,11 @@ max_allowed_packet", ...@@ -2332,11 +2332,11 @@ max_allowed_packet",
if (mysql_error_number == ER_MASTER_FATAL_ERROR_READING_BINLOG) if (mysql_error_number == ER_MASTER_FATAL_ERROR_READING_BINLOG)
{ {
sql_print_error(ER(mysql_error_number), mysql_error_number, sql_print_error(ER(mysql_error_number), mysql_error_number,
mc_mysql_error(mysql)); mysql_error(mysql));
goto err; goto err;
} }
thd->proc_info = "Waiting to reconnect after a failed read"; thd->proc_info = "Waiting to reconnect after a failed read";
mc_end_server(mysql); end_server(mysql);
if (retry_count++) if (retry_count++)
{ {
if (retry_count > master_retry_count) if (retry_count > master_retry_count)
...@@ -2406,7 +2406,7 @@ err: ...@@ -2406,7 +2406,7 @@ err:
VOID(pthread_mutex_unlock(&LOCK_thread_count)); VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (mysql) if (mysql)
{ {
mc_mysql_close(mysql); mysql_close(mysql);
mi->mysql=0; mi->mysql=0;
} }
thd->proc_info = "Waiting for slave mutex on exit"; thd->proc_info = "Waiting for slave mutex on exit";
...@@ -2947,22 +2947,22 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, ...@@ -2947,22 +2947,22 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
client_flag=CLIENT_COMPRESS; /* We will use compression */ client_flag=CLIENT_COMPRESS; /* We will use compression */
while (!(slave_was_killed = io_slave_killed(thd,mi)) && while (!(slave_was_killed = io_slave_killed(thd,mi)) &&
(reconnect ? mc_mysql_reconnect(mysql) != 0: (reconnect ? mysql_reconnect(mysql) != 0:
!mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0, !mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0,
mi->port, 0, client_flag, mi->port, 0, client_flag,
thd->variables.net_read_timeout))) thd->variables.net_read_timeout)))
{ {
/* Don't repeat last error */ /* Don't repeat last error */
if (mc_mysql_errno(mysql) != last_errno) if ((int)mysql_errno(mysql) != last_errno)
{ {
last_errno=mc_mysql_errno(mysql); last_errno=mysql_errno(mysql);
suppress_warnings= 0; suppress_warnings= 0;
sql_print_error("Slave I/O thread: error %s to master \ sql_print_error("Slave I/O thread: error %s to master \
'%s@%s:%d': \ '%s@%s:%d': \
Error: '%s' errno: %d retry-time: %d retries: %d", Error: '%s' errno: %d retry-time: %d retries: %d",
(reconnect ? "reconnecting" : "connecting"), (reconnect ? "reconnecting" : "connecting"),
mi->user,mi->host,mi->port, mi->user,mi->host,mi->port,
mc_mysql_error(mysql), last_errno, mysql_error(mysql), last_errno,
mi->connect_retry, mi->connect_retry,
master_retry_count); master_retry_count);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment