📄 libmysql.c
字号:
/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB This file is public domain and comes with NO WARRANTY of any kind */#include <global.h>#if defined(__WIN__) || defined(_WIN32) || defined(_WIN64)#include <winsock.h>#include <odbcinst.h>#endif#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>#include <signal.h>#include <time.h>#ifdef HAVE_PWD_H#include <pwd.h>#endif#if !defined(MSDOS) && !defined(__WIN__)#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#ifdef HAVE_SELECT_H# include <select.h>#endif#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#endif#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#endifstatic my_bool mysql_client_init=0;uint mysql_port=0;my_string mysql_unix_port=0;#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_TRANSACTIONS)#ifdef __WIN__#define CONNECT_TIMEOUT 20#else#define CONNECT_TIMEOUT 0#endif#if defined(MSDOS) || defined(__WIN__)/* socket_errno is defined in global.h for all platforms */#define perror(A)#else#include <errno.h>#define SOCKET_ERROR -1#endif /* __WIN__ */static void mysql_once_init(void);static MYSQL_DATA *read_rows (MYSQL *mysql,MYSQL_FIELD *fields, uint field_count);static int read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths);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);/* Let the user specify that we don't want SIGPIPE; This doesn't however work with threaded applications as we can have multiple read in progress.*/#if !defined(__WIN__) && defined(SIGPIPE) && !defined(THREAD)#define init_sigpipe_variables sig_return old_signal_handler=(sig_return) 0;#define set_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) old_signal_handler=signal(SIGPIPE,pipe_sig_handler)#define reset_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) signal(SIGPIPE,old_signal_handler);#else#define init_sigpipe_variables#define set_sigpipe(mysql)#define reset_sigpipe(mysql)#endif/***************************************************************************** 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,* connect2() will behave exactly like connect().** Base version coded by Steve Bernacki, Jr. <steve@navinet.net>*****************************************************************************/static int connect2(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}/*** 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; if (sizeof(szPipeName) <= (strlen(host) + strlen(unix_socket) + sizeof("\\\\\\pipe\\"))) { return INVALID_HANDLE_VALUE; } 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*****************************************************************************/uintnet_safe_read(MYSQL *mysql){ NET *net= &mysql->net; uint 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; if (mysql->protocol_version > 9) { /* New client protocol */ net->last_errno=uint2korr(pos); pos+=2; len-=2; } 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;}/* Get the length of next field. Change parameter to point at fieldstart */static ulongnet_field_length(uchar **packet){ reg1 uchar *pos= *packet; if (*pos < 251) { (*packet)++; return (ulong) *pos; } if (*pos == 251) { (*packet)++; return NULL_LENGTH; } if (*pos == 252) { (*packet)+=3; return (ulong) uint2korr(pos+1); } if (*pos == 253) { (*packet)+=4; return (ulong) uint3korr(pos+1); } (*packet)+=9; /* Must be 254 when here */ return (ulong) uint4korr(pos+1);}/* Same as above, but returns ulonglong values */static my_ulonglongnet_field_length_ll(uchar **packet){ reg1 uchar *pos= *packet; if (*pos < 251) { (*packet)++; return (my_ulonglong) *pos; } if (*pos == 251) { (*packet)++; return (my_ulonglong) NULL_LENGTH; } if (*pos == 252) { (*packet)+=3; return (my_ulonglong) uint2korr(pos+1); } if (*pos == 253) { (*packet)+=4; return (my_ulonglong) uint3korr(pos+1); } (*packet)+=9; /* Must be 254 when here */#ifdef NO_CLIENT_LONGLONG return (my_ulonglong) uint4korr(pos+1);#else return (my_ulonglong) uint8korr(pos+1);#endif}static void free_rows(MYSQL_DATA *cur){ if (cur) { free_root(&cur->alloc,MYF(0)); my_free((gptr) cur,MYF(0)); }}intsimple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, uint length, my_bool skipp_check){ NET *net= &mysql->net; int 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)) { net->last_errno=CR_SERVER_GONE_ERROR; strmov(net->last_error,ER(net->last_errno)); 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->info=0; mysql->affected_rows= ~(my_ulonglong) 0; net_clear(net); /* Clear receive buffer */ if (!arg) arg=""; if (net_write_command(net,(uchar) command,arg, length ? length : (ulong) strlen(arg))) { DBUG_PRINT("error",("Can't send command to server. Error: %d",socket_errno)); end_server(mysql); if (mysql_reconnect(mysql) || net_write_command(net,(uchar) command,arg, length ? length : (ulong) strlen(arg))) { 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=net_safe_read(mysql)) == packet_error ? -1 : 0); end: reset_sigpipe(mysql); return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -