📄 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 */
#ifdef _WIN32
#include <winsock.h>
#include <odbcinst.h>
#endif
#include <global.h>
#include <my_sys.h>
#include <m_string.h>
#include <m_ctype.h>
#include "mysql.h"
#include "mysql_version.h"
#include "errmsg.h"
#include <sys/stat.h>
#include <signal.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#if !defined(MSDOS) && !defined(__WIN32__)
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
#ifdef HAVE_SYS_UN_H
# include <sys/un.h>
#endif
#if defined(THREAD) && !defined(__WIN32__)
#include <my_pthread.h> /* because of signal() */
#endif
#ifndef INADDR_NONE
#define INADDR_NONE -1
#endif
static my_bool mysql_client_init=0;
static MYSQL *current_mysql;
uint mysql_port=0;
my_string mysql_unix_port=0;
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG)
#if defined(MSDOS) || defined(__WIN32__)
#define ERRNO WSAGetLastError()
#define perror(A)
#else
#define ERRNO errno
#define SOCKET_ERROR -1
#define closesocket(A) close(A)
#endif
static MYSQL_DATA *read_rows (MYSQL *mysql,MYSQL_FIELD *fields,
uint field_count);
static void end_server(MYSQL *mysql);
static void remember_connection(MYSQL *mysql);
static void read_user_name(char *name);
static void append_wild(char *to,char *end,const char *wild);
/*****************************************************************************
** read a packet from server. Give error message if socket was down
** or package is an error message
*****************************************************************************/
static uint
net_safe_read(MYSQL *mysql)
{
NET *net= &mysql->net;
uint len=0;
if (net->fd < 0 || ((len=my_net_read(net)) == packet_error || len == 0))
{
DBUG_PRINT("error",("Wrong connection or packet. fd: %d len: %d",
net->fd,len));
end_server(mysql);
net->last_errno=CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
return(packet_error);
}
if (net->buff[0] == 255)
{
if (len > 3)
{
char *pos=(char*) net->buff+1;
if (mysql->protocol_version > 9)
{ /* New client protocol */
net->last_errno=uint2korr(pos);
pos+=2;
}
else
net->last_errno=CR_UNKNOWN_ERROR;
(void) strmake(net->last_error,(char*) pos, 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 ulong
net_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 uint2korr(pos+1);
}
if (*pos == 253)
{
(*packet)+=4;
return uint3korr(pos+1);
}
(*packet)+=6; /* Must be 254 when here */
return uint4korr(pos+1);
}
static void free_rows(MYSQL_DATA *cur)
{
if (cur)
{
free_root(&cur->alloc);
my_free((gptr) cur,MYF(0));
}
}
static my_bool mysql_reconnect(MYSQL *mysql)
{
MYSQL tmp_mysql;
DBUG_ENTER("mysql_reconnect");
if (!mysql->reconnect || !mysql->host_info)
DBUG_RETURN(1);
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;
mysql_close(mysql);
memcpy(mysql,&tmp_mysql,sizeof(tmp_mysql));
net_clear(&mysql->net);
mysql->affected_rows= (ulong) ~0L;
DBUG_RETURN(0);
}
static int
simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
uint length, my_bool skipp_check)
{
NET *net= &mysql->net;
if (mysql->net.fd < 0)
{ /* Do reconnect if possible */
if (mysql_reconnect(mysql))
{
net->last_errno=CR_SERVER_GONE_ERROR;
strmov(net->last_error,ER(net->last_errno));
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->info=0;
mysql->affected_rows= (ulong) ~0L;
remember_connection(mysql);
net_clear(net); /* Clear receive buffer */
if (!arg)
arg="";
if (net_write_command(net,(uchar) command,arg,
length ? length :strlen(arg)))
{
DBUG_PRINT("error",("Can't send command to server. Error: %d",errno));
end_server(mysql);
if (mysql_reconnect(mysql) ||
net_write_command(net,(uchar) command,arg,
length ? length :strlen(arg)))
{
net->last_errno=CR_SERVER_GONE_ERROR;
strmov(net->last_error,ER(net->last_errno));
return -1;
}
}
if (!skipp_check)
return (net_safe_read(mysql) == packet_error ? -1 : 0);
return 0;
}
static void free_old_query(MYSQL *mysql)
{
DBUG_ENTER("free_old_query");
if (mysql->fields)
free_root(&mysql->field_alloc);
init_alloc_root(&mysql->field_alloc,8192); /* Assume rowlength < 8192 */
mysql->fields=0;
mysql->field_count=0; /* For API */
DBUG_VOID_RETURN;
}
#define USERNAMELENGTH 16
#if !defined(MSDOS) && ! defined(VMS) && !defined(__WIN32__)
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,*getpwuid();
char *str,*getlogin();
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,USERNAMELENGTH);
#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)
{
strmov(name,"ODBC"); /* ODBC will send user variable */
}
#endif
/*
** Expand wildcard to a sql string
*/
static void
append_wild(char *to, char *end, const char *wild)
{
end-=5; /* Some extra */
if (wild && wild[0])
{
to=strmov(to," like '");
while (*wild && to < end)
{
if (*wild == '\\' || *wild == '\'')
*to++='\\';
*to++= *wild++;
}
if (*wild) /* Too small buffer */
*to++='%'; /* Nicer this way */
to[0]='\'';
to[1]=0;
}
}
/**************************************************************************
** Init debugging if MYSQL_DEBUG environment variable is found
**************************************************************************/
void STDCALL
mysql_debug(char *debug)
{
#ifndef DBUG_OFF
char *env;
if (_db_on_)
return; /* Already using debugging */
if (debug)
{
DEBUGGER_ON;
DBUG_PUSH(debug);
}
else if ((env = getenv("MYSQL_DEBUG")))
{
DEBUGGER_ON;
DBUG_PUSH(env);
#if !defined(_WINVER) && !defined(WINVER)
puts("\n-------------------------------------------------------");
puts("MYSQL_DEBUG found. libmysql started with the following:");
puts(env);
puts("-------------------------------------------------------\n");
#else
{
char buff[80];
strmov(strmov(buff,"libmysql: "),env);
MessageBox((HWND) 0,"Debugging variable MYSQL_DEBUG used",buff,MB_OK);
}
#endif
}
#endif
}
/**************************************************************************
** Store the server socket currently in use
** Used by pipe_handler if error on socket interrupt
**************************************************************************/
static void
remember_connection(MYSQL *mysql)
{
current_mysql = mysql;
}
/**************************************************************************
** Close the server connection if we get a SIGPIPE
ARGSUSED
**************************************************************************/
static sig_handler
pipe_sig_handle(int sig __attribute__((unused)))
{
DBUG_PRINT("info",("Hit by signal %d",sig));
#ifdef NOT_USED
end_server(current_mysql);
#endif
#ifdef DONT_REMEMBER_SIGNAL
(void) signal(SIGPIPE,pipe_sig_handle);
#endif
}
/**************************************************************************
** Shut down connection
**************************************************************************/
static void
end_server(MYSQL *mysql)
{
DBUG_ENTER("end_server");
if (mysql->net.fd >= 0)
{
DBUG_PRINT("enter",("Socket: %d", mysql->net.fd));
(void) shutdown(mysql->net.fd,2);
(void) closesocket(mysql->net.fd);
mysql->net.fd= -1;
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)
{
free_rows(result->data);
if (result->fields)
free_root(&result->field_alloc);
if (result->row)
my_free((gptr) result->row,MYF(0));
my_free((gptr) result,MYF(0));
}
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, 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 (default_value && row->data[5])
field->def=strdup_root(alloc,(char*) row->data[5]);
else
field->def=0;
field->max_length= 0;
}
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,pkt_len;
ulong len;
uchar *cp;
char *to;
MYSQL_DATA *result;
MYSQL_ROWS **prev_ptr,*cur;
NET *net = &mysql->net;
DBUG_ENTER("read_rows");
if ((pkt_len=(uint) 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); /* Assume rowlength < 8192 */
result->alloc.min_malloc=sizeof(MYSQL_ROWS);
prev_ptr= &result->data;
result->rows=0;
result->fields=fields;
while (*(cp=net->buff) != 254 || pkt_len != 1)
{
result->rows++;
if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -