diff options
Diffstat (limited to 'libmysqld/libmysqld.c')
-rw-r--r-- | libmysqld/libmysqld.c | 497 |
1 files changed, 115 insertions, 382 deletions
diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index cb8b2f02773..49f467da601 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -15,19 +15,11 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#define DONT_USE_RAID -#include <my_global.h> -#if defined(__WIN__) || defined(_WIN32) || defined(_WIN64) -#include <winsock.h> -#include <odbcinst.h> -#endif +#include "embedded_priv.h" #include <my_sys.h> #include <mysys_err.h> #include <m_string.h> #include <m_ctype.h> -#include "mysql.h" -#include "mysql_version.h" -#include "mysqld_error.h" #include "errmsg.h" #include <violite.h> #include <sys/stat.h> @@ -51,9 +43,6 @@ #ifdef HAVE_SYS_UN_H # include <sys/un.h> #endif -#if defined(THREAD) && !defined(__WIN__) -#include <my_pthread.h> /* because of signal() */ -#endif #ifndef INADDR_NONE #define INADDR_NONE -1 #endif @@ -74,12 +63,6 @@ my_string mysql_unix_port=0; #define closesocket(A) close(A) #endif -/* XXX: this is real ugly... */ -extern void start_embedded_connection(NET * net); -extern void lib_connection_phase(NET *net, int phase); -extern bool lib_dispatch_command(enum enum_server_command command, NET *net, - const char *arg, ulong length); - static void mysql_once_init(void); static MYSQL_DATA *read_rows (MYSQL *mysql,MYSQL_FIELD *fields, uint field_count); @@ -88,9 +71,7 @@ static int read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, static void end_server(MYSQL *mysql); static void read_user_name(char *name); static void append_wild(char *to,char *end,const char *wild); -static my_bool mysql_reconnect(MYSQL *mysql); static int send_file_to_server(MYSQL *mysql,const char *filename); -static sig_handler pipe_sig_handler(int sig); static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, const char *from, ulong length); @@ -98,17 +79,12 @@ static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, #define set_sigpipe(mysql) #define reset_sigpipe(mysql) -static MYSQL* spawn_init(MYSQL* parent, const char* host, - unsigned int port, - const char* user, - const char* passwd); - /***************************************************************************** ** read a packet from server. Give error message if socket was down ** or packet is an error message *****************************************************************************/ -static uint +ulong net_safe_read(MYSQL *mysql) { NET *net= &mysql->net; @@ -237,9 +213,9 @@ static void free_rows(MYSQL_DATA *cur) } -static int +int simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, - uint length, my_bool skipp_check) + ulong length, my_bool skipp_check) { NET *net= &mysql->net; int result= -1; @@ -403,22 +379,6 @@ mysql_debug(const char *debug) #endif } - -/************************************************************************** -** Close the server connection if we get a SIGPIPE - ARGSUSED -**************************************************************************/ - -static sig_handler -pipe_sig_handler(int sig __attribute__((unused))) -{ - DBUG_PRINT("info",("Hit by signal %d",sig)); -#ifdef DONT_REMEMBER_SIGNAL - (void) signal(SIGPIPE,pipe_sig_handler); -#endif -} - - /************************************************************************** ** Shut down connection **************************************************************************/ @@ -429,11 +389,7 @@ 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); + end_embedded_connection(&mysql->net); mysql->net.vio= 0; /* Marker */ } net_end(&mysql->net); @@ -739,7 +695,7 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) ulong pkt_len,len; uchar *pos,*prev_pos; - if ((pkt_len=(uint) net_safe_read(mysql)) == packet_error) + if ((pkt_len=net_safe_read(mysql)) == packet_error) return -1; if (pkt_len == 1 && mysql->net.read_pos[0] == 254) return 1; /* End of data */ @@ -767,301 +723,6 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) return 0; } -/* perform query on master */ -int STDCALL mysql_master_query(MYSQL *mysql, const char *q, - unsigned int length) -{ - if(mysql_master_send_query(mysql, q, length)) - return 1; - return mysql_read_query_result(mysql); -} - -int STDCALL mysql_master_send_query(MYSQL *mysql, const char *q, - unsigned int length) -{ - MYSQL*master = mysql->master; - if (!length) - length = strlen(q); - if (!master->net.vio && !mysql_real_connect(master,0,0,0,0,0,0,0)) - return 1; - mysql->last_used_con = master; - return simple_command(master, COM_QUERY, q, length, 1); -} - - -/* perform query on slave */ -int STDCALL mysql_slave_query(MYSQL *mysql, const char *q, - unsigned int length) -{ - if(mysql_slave_send_query(mysql, q, length)) - return 1; - return mysql_read_query_result(mysql); -} - -int STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q, - unsigned int length) -{ - MYSQL* last_used_slave, *slave_to_use = 0; - - 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(!length) - length = strlen(q); - if(!slave_to_use->net.vio && !mysql_real_connect(slave_to_use, 0,0,0, - 0,0,0,0)) - return 1; - 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 */ -int 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 inline void expand_error(MYSQL* mysql, int error) -{ - char tmp[MYSQL_ERRMSG_SIZE]; - char* p, *tmp_end; - tmp_end = strnmov(tmp, mysql->net.last_error, MYSQL_ERRMSG_SIZE); - p = strnmov(mysql->net.last_error, ER(error), MYSQL_ERRMSG_SIZE); - memcpy(p, tmp, tmp_end - tmp); - mysql->net.last_errno = error; -} - -/* This function assumes we have just called SHOW SLAVE STATUS and have - read the given result and row -*/ -static inline int get_master(MYSQL* mysql, MYSQL_RES* res, MYSQL_ROW row) -{ - MYSQL* master; - if(mysql_num_fields(res) < 3) - 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))) - return 1; - mysql->master = master; - return 0; -} - -/* assuming we already know that mysql points to a master connection, - retrieve all the slaves -*/ -static inline int get_slaves_from_master(MYSQL* mysql) -{ - MYSQL_RES* res = 0; - MYSQL_ROW row; - int error = 1; - int has_auth_info; - if (!mysql->net.vio && !mysql_real_connect(mysql,0,0,0,0,0,0,0)) - { - expand_error(mysql, CR_PROBE_MASTER_CONNECT); - return 1; - } - - if (mysql_query(mysql, "SHOW SLAVE HOSTS") || - !(res = mysql_store_result(mysql))) - { - expand_error(mysql, CR_PROBE_SLAVE_HOSTS); - return 1; - } - - switch (mysql_num_fields(res)) - { - case 3: has_auth_info = 0; break; - case 5: has_auth_info = 1; 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[3]; - tmp_pass = row[4]; - } - else - { - tmp_user = mysql->user; - tmp_pass = mysql->passwd; - } - - if(!(slave = spawn_init(mysql, row[1], atoi(row[2]), - 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); - return error; -} - -int STDCALL mysql_rpl_probe(MYSQL* mysql) -{ - MYSQL_RES* res = 0; - MYSQL_ROW row; - int error = 1; - /* 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); - return 1; - } - - if (!(row = mysql_fetch_row(res))) - goto err; - - /* check master host for emptiness/NULL */ - if (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); - 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_end = (len) ? q + len : strend(q); - for(; q < q_end; ++q) - { - char c; - if(isalpha(c=*q)) - switch(tolower(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 tolower(q[1]) == 'h' ? MYSQL_RPL_ADMIN : MYSQL_RPL_MASTER ; - case 's': /* select or show */ - return tolower(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 0; -} - -static MYSQL* spawn_init(MYSQL* parent, const char* host, - unsigned int port, - const char* user, - const char* passwd) -{ - MYSQL* child; - if (!(child = mysql_init(0))) - return 0; - - child->options.user = my_strdup((user) ? user : - (parent->user ? parent->user : - parent->options.user), MYF(0)); - child->options.password = my_strdup((passwd) ? passwd : (parent->passwd ? - parent->passwd : - parent->options.password), MYF(0)); - child->options.port = port; - child->options.host = my_strdup((host) ? host : (parent->host ? - parent->host : - parent->options.host), MYF(0)); - if(parent->db) - child->options.db = my_strdup(parent->db, MYF(0)); - else if(parent->options.db) - child->options.db = my_strdup(parent->options.db, MYF(0)); - - child->options.rpl_parse = child->options.rpl_probe = child->rpl_pivot = 0; - - return child; -} - /**************************************************************************** ** Init MySQL structure or allocate one ****************************************************************************/ @@ -1308,7 +969,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, mysql->db=my_strdup(db,MYF(MY_WME)); db=0; } - if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net)) + if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net)) goto error; lib_connection_phase(net,2); @@ -1346,35 +1007,6 @@ error: } -static my_bool mysql_reconnect(MYSQL *mysql) -{ - MYSQL tmp_mysql; - DBUG_ENTER("mysql_reconnect"); - - if (!mysql->reconnect || - (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info) - { - /* Allov reconnect next time */ - mysql->server_status&= ~SERVER_STATUS_IN_TRANS; - DBUG_RETURN(1); - } - mysql_init(&tmp_mysql); - tmp_mysql.options=mysql->options; - if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd, - mysql->db, mysql->port, mysql->unix_socket, - mysql->client_flag)) - DBUG_RETURN(1); - tmp_mysql.free_me=mysql->free_me; - mysql->free_me=0; - bzero((char*) &mysql->options,sizeof(mysql->options)); - mysql_close(mysql); - *mysql=tmp_mysql; - net_clear(&mysql->net); - mysql->affected_rows= ~(my_ulonglong) 0; - DBUG_RETURN(0); -} - - /************************************************************************** ** Change user and database **************************************************************************/ @@ -1394,7 +1026,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, pos=scramble(pos, mysql->scramble_buff, passwd, (my_bool) (mysql->protocol_version == 9)); pos=strmov(pos+1,db ? db : ""); - if (simple_command(mysql,COM_CHANGE_USER, buff,(uint) (pos-buff),0)) + if (simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (pos-buff),0)) DBUG_RETURN(1); my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR)); @@ -1419,7 +1051,7 @@ mysql_select_db(MYSQL *mysql, const char *db) DBUG_ENTER("mysql_select_db"); DBUG_PRINT("enter",("db: '%s'",db)); - if ((error=simple_command(mysql,COM_INIT_DB,db,(uint) strlen(db),0))) + 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)); @@ -1482,11 +1114,11 @@ mysql_close(MYSQL *mysql) int STDCALL mysql_query(MYSQL *mysql, const char *query) { - return mysql_real_query(mysql,query, (uint) strlen(query)); + return mysql_real_query(mysql,query, (ulong) strlen(query)); } int STDCALL -mysql_send_query(MYSQL* mysql, const char* query, uint length) +mysql_send_query(MYSQL* mysql, const char* query, ulong length) { return simple_command(mysql, COM_QUERY, query, length, 1); } @@ -1541,8 +1173,109 @@ get_info: DBUG_RETURN(0); } +/**************************************************************************** +* A modified version of connect(). connect2() allows you to specify +* a timeout value, in seconds, that we should wait until we +* derermine we can't connect to a particular host. If timeout is 0, +* my_connect() will behave exactly like connect(). +* +* Base version coded by Steve Bernacki, Jr. <steve@navinet.net> +*****************************************************************************/ + +int my_connect(my_socket s, const struct sockaddr *name, uint namelen, + uint timeout) +{ +#if defined(__WIN__) || defined(OS2) + 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; + 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); + + 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); + /* + * 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 ((res = select(s+1, NULL, &sfds, NULL, &tv)) >= 0) + break; + 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); /* It's all good! */ +#endif +} + + int STDCALL -mysql_real_query(MYSQL *mysql, const char *query, uint length) +mysql_real_query(MYSQL *mysql, const char *query, ulong length) { DBUG_ENTER("mysql_real_query"); DBUG_PRINT("enter",("handle: %lx",mysql)); @@ -1940,7 +1673,7 @@ mysql_create_db(MYSQL *mysql, const char *db) { DBUG_ENTER("mysql_createdb"); DBUG_PRINT("enter",("db: %s",db)); - DBUG_RETURN(simple_command(mysql,COM_CREATE_DB,db, (uint) strlen(db),0)); + DBUG_RETURN(simple_command(mysql,COM_CREATE_DB,db, (ulong) strlen(db),0)); } @@ -1949,7 +1682,7 @@ mysql_drop_db(MYSQL *mysql, const char *db) { DBUG_ENTER("mysql_drop_db"); DBUG_PRINT("enter",("db: %s",db)); - DBUG_RETURN(simple_command(mysql,COM_DROP_DB,db,(uint) strlen(db),0)); + DBUG_RETURN(simple_command(mysql,COM_DROP_DB,db,(ulong) strlen(db),0)); } |