]> granicus.if.org Git - php/commitdiff
First version from the MySQL team.
authorMySQL Team <mysql@php.net>
Sat, 19 Feb 2000 21:35:02 +0000 (21:35 +0000)
committerMySQL Team <mysql@php.net>
Sat, 19 Feb 2000 21:35:02 +0000 (21:35 +0000)
ext/mysql/libmysql/dll.c [new file with mode: 0644]
ext/mysql/libmysql/errmsg.c [new file with mode: 0644]
ext/mysql/libmysql/get_password.c [new file with mode: 0644]
ext/mysql/libmysql/libmysql.c [new file with mode: 0644]
ext/mysql/libmysql/net.c [new file with mode: 0644]
ext/mysql/libmysql/password.c [new file with mode: 0644]
ext/mysql/libmysql/violite.c [new file with mode: 0644]

diff --git a/ext/mysql/libmysql/dll.c b/ext/mysql/libmysql/dll.c
new file mode 100644 (file)
index 0000000..a3116b3
--- /dev/null
@@ -0,0 +1,98 @@
+/* Copyright Abandoned 1999 TCX DataKonsult AB & Monty Program KB & Detron HB
+   This file is public domain and comes with NO WARRANTY of any kind */
+
+/*
+** Handling initialization of the dll library
+*/
+
+#include <global.h>
+#include <my_sys.h>
+#include <my_pthread.h>
+
+static bool libmysql_inited=0;
+
+void libmysql_init(void)
+{
+  if (libmysql_inited)
+    return;
+  libmysql_inited=1;
+  my_init();
+  {
+    DBUG_ENTER("libmysql_init");
+#ifdef LOG_ALL
+    DBUG_PUSH("d:t:S:O,c::\\tmp\\libmysql.log");
+#else
+    if (getenv("LIBMYSQL_LOG") != NULL)
+      DBUG_PUSH(getenv("LIBMYSQL_LOG"));
+#endif
+    DBUG_VOID_RETURN;
+  }
+}
+
+#ifdef WIN32
+
+static int inited=0,threads=0;
+HINSTANCE NEAR s_hModule;      /* Saved module handle */
+DWORD main_thread;
+
+BOOL APIENTRY LibMain(HANDLE hInst,DWORD ul_reason_being_called,
+                     LPVOID lpReserved)
+{
+  switch (ul_reason_being_called) {
+  case DLL_PROCESS_ATTACH:     /* case of libentry call in win 3.x */
+    if (!inited++)
+    {
+      s_hModule=hInst;
+      libmysql_init();
+      main_thread=GetCurrentThreadId();
+    }
+    break;
+  case DLL_THREAD_ATTACH:
+    threads++;
+    my_thread_init();
+    break;
+  case DLL_PROCESS_DETACH:     /* case of wep call in win 3.x */
+     if (!--inited)            /* Safety */
+     {
+       /* my_thread_init() */  /* This may give extra safety */
+       my_end(0);
+     }
+    break;
+  case DLL_THREAD_DETACH:
+    /* Main thread will free by my_end() */
+    threads--;
+    if (main_thread != GetCurrentThreadId())
+      my_thread_end();
+    break;
+  default:
+    break;
+  } /* switch */
+
+  return TRUE;
+
+  UNREFERENCED_PARAMETER(lpReserved);
+} /* LibMain */
+
+int __stdcall DllMain(HANDLE hInst,DWORD ul_reason_being_called,LPVOID lpReserved)
+{
+  return LibMain(hInst,ul_reason_being_called,lpReserved);
+}
+
+#elif defined(WINDOWS)
+
+/****************************************************************************
+**     This routine is called by LIBSTART.ASM at module load time.  All it
+**     does in this sample is remember the DLL module handle.  The module
+**     handle is needed if you want to do things like load stuff from the
+**     resource file (for instance string resources).
+****************************************************************************/
+
+int _export FAR PASCAL libmain(HANDLE hModule,short cbHeapSize,
+                              UCHAR FAR *lszCmdLine)
+{
+  s_hModule = hModule;
+  libmysql_init();
+  return TRUE;
+}
+
+#endif
diff --git a/ext/mysql/libmysql/errmsg.c b/ext/mysql/libmysql/errmsg.c
new file mode 100644 (file)
index 0000000..96f1f41
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+   This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Error messages for MySQL clients */
+/* error messages for the demon is in share/language/errmsg.sys */
+
+#include <global.h>
+#include <my_sys.h>
+#include "errmsg.h"
+
+#ifdef GERMAN
+const char *client_errors[]=
+{
+  "Unbekannter MySQL Fehler",
+  "Kann UNIX-Socket nicht anlegen (%d)",
+  "Keine Verbindung zu lokalem MySQL Server, socket: '%-.64s' (%d)",
+  "Keine Verbindung zu MySQL Server auf %-.64s (%d)",
+  "Kann TCP/IP-Socket nicht anlegen (%d)",
+  "Unbekannter MySQL Server Host (%-.64s) (%d)",
+  "MySQL Server nicht vorhanden",
+  "Protokolle ungleich. Server Version = % d Client Version = %d",
+  "MySQL client got out of memory",
+  "Wrong host info",
+  "Localhost via UNIX socket",
+  "%s via TCP/IP",
+  "Error in server handshake",
+  "Lost connection to MySQL server during query",
+  "Commands out of sync; You can't run this command now",
+  "Verbindung ueber Named Pipe; Host: %-.64s",
+  "Kann nicht auf Named Pipe warten. Host: %-.64s  pipe: %-.32s (%lu)",
+  "Kann Named Pipe nicht oeffnen. Host: %-.64s  pipe: %-.32s (%lu)",
+  "Kann den Status der Named Pipe nicht setzen.  Host: %-.64s  pipe: %-.32s (%lu)"
+};
+
+#else /* ENGLISH */
+const char *client_errors[]=
+{
+  "Unknown MySQL error",
+  "Can't create UNIX socket (%d)",
+  "Can't connect to local MySQL server through socket '%-.64s' (%d)",
+  "Can't connect to MySQL server on '%-.64s' (%d)",
+  "Can't create TCP/IP socket (%d)",
+  "Unknown MySQL Server Host '%-.64s' (%d)",
+  "MySQL server has gone away",
+  "Protocol mismatch. Server Version = %d Client Version = %d",
+  "MySQL client run out of memory",
+  "Wrong host info",
+  "Localhost via UNIX socket",
+  "%s via TCP/IP",
+  "Error in server handshake",
+  "Lost connection to MySQL server during query",
+  "Commands out of sync;  You can't run this command now",
+  "%s via named pipe",
+  "Can't wait for named pipe to host: %-.64s  pipe: %-.32s (%lu)",
+  "Can't open named pipe to host: %-.64s  pipe: %-.32s (%lu)",
+  "Can't set state of named pipe to host: %-.64s  pipe: %-.32s (%lu)",
+};
+#endif
+
+
+void init_client_errs(void)
+{
+  errmsg[CLIENT_ERRMAP] = &client_errors[0];
+}
diff --git a/ext/mysql/libmysql/get_password.c b/ext/mysql/libmysql/get_password.c
new file mode 100644 (file)
index 0000000..e0a460c
--- /dev/null
@@ -0,0 +1,199 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+   This file is public domain and comes with NO WARRANTY of any kind */
+
+/*
+** Ask for a password from tty
+** This is an own file to avoid conflicts with curses
+*/
+#include <global.h>
+#include <my_sys.h>
+#include "mysql.h"
+#include <m_string.h>
+#include <m_ctype.h>
+#include <dbug.h>
+
+#if defined(HAVE_BROKEN_GETPASS) && !defined(HAVE_GETPASSPHRASE)
+#undef HAVE_GETPASS
+#endif
+
+#ifdef HAVE_GETPASS
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif /* HAVE_PWD_H */
+#else /* ! HAVE_GETPASS */
+#ifndef __WIN32__
+#include <sys/ioctl.h>
+#ifdef HAVE_TERMIOS_H                          /* For tty-password */
+#include       <termios.h>
+#define TERMIO struct termios
+#else
+#ifdef HAVE_TERMIO_H                           /* For tty-password */
+#include       <termio.h>
+#define TERMIO struct termio
+#else
+#include       <sgtty.h>
+#define TERMIO struct sgttyb
+#endif
+#endif
+#ifdef alpha_linux_port
+#include <asm/ioctls.h>                                /* QQ; Fix this in configure */
+#include <asm/termiobits.h>
+#endif
+#else
+#include <conio.h>
+#endif /* __WIN32__ */
+#endif /* HAVE_GETPASS */
+
+#ifdef HAVE_GETPASSPHRASE                      /* For Solaris */
+#define getpass(A) getpassphrase(A)
+#endif
+
+#ifdef __WIN32__
+/* were just going to fake it here and get input from
+   the keyboard */
+
+char *get_tty_password(char *opt_message)
+{
+  char to[80];
+  char *pos=to,*end=to+sizeof(to)-1;
+  int i=0;
+  DBUG_ENTER("get_tty_password");
+  fprintf(stdout,opt_message ? opt_message : "Enter password: ");
+  for (;;)
+  {
+    char tmp;
+    tmp=_getch();
+    if (tmp == '\b' || (int) tmp == 127)
+    {
+      if (pos != to)
+      {
+       _cputs("\b \b");
+       pos--;
+       continue;
+      }
+    }
+    if (tmp == '\n' || tmp == '\r' || tmp == 3)
+      break;
+    if (iscntrl(tmp) || pos == end)
+      continue;
+    _cputs("*");
+    *(pos++) = tmp;
+  }
+  while (pos != to && isspace(pos[-1]) == ' ')
+    pos--;                                     /* Allow dummy space at end */
+  *pos=0;
+  _cputs("\n");
+  DBUG_RETURN(my_strdup(to,MYF(MY_FAE)));
+}
+
+#else
+
+static void get_password(char *to,uint length,int file_no,bool echo);
+
+char *get_tty_password(char *opt_message)
+{
+#ifdef HAVE_GETPASS
+  char *passbuff;
+#else /* ! HAVE_GETPASS */
+  TERMIO org,tmp;
+#endif /* HAVE_GETPASS */
+  char buff[80];
+
+  DBUG_ENTER("get_tty_password");
+
+#ifdef HAVE_GETPASS
+  passbuff = getpass(opt_message ? opt_message : "Enter password: ");
+
+  /* copy the password to buff and clear original (static) buffer */
+  strnmov(buff, passbuff, sizeof(buff) - 1);
+#ifdef _PASSWORD_LEN
+  memset(passbuff, 0, _PASSWORD_LEN);
+#endif
+#else 
+  if (isatty(fileno(stdout)))
+  {
+    fputs(opt_message ? opt_message : "Enter password: ",stdout);
+    fflush(stdout);
+  }
+#if defined(HAVE_TERMIOS_H)
+  tcgetattr(fileno(stdin), &org);
+  tmp = org;
+  tmp.c_lflag &= ~(ECHO | ISIG | ICANON);
+  tmp.c_cc[VMIN] = 1;
+  tmp.c_cc[VTIME] = 0;
+  tcsetattr(fileno(stdin), TCSADRAIN, &tmp);
+  get_password(buff, sizeof(buff)-1, fileno(stdin), isatty(fileno(stdout)));
+  tcsetattr(fileno(stdin), TCSADRAIN, &org);
+#elif defined(HAVE_TERMIO_H)
+  ioctl(fileno(stdin), (int) TCGETA, &org);
+  tmp=org;
+  tmp.c_lflag &= ~(ECHO | ISIG | ICANON);
+  tmp.c_cc[VMIN] = 1;
+  tmp.c_cc[VTIME]= 0;
+  ioctl(fileno(stdin),(int) TCSETA, &tmp);
+  get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout)));
+  ioctl(fileno(stdin),(int) TCSETA, &org);
+#else
+  gtty(fileno(stdin), &org);
+  tmp=org;
+  tmp.sg_flags &= ~ECHO;
+  tmp.sg_flags |= RAW;
+  stty(fileno(stdin), &tmp);
+  get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout)));
+  stty(fileno(stdin), &org);
+#endif
+  if (isatty(fileno(stdout)))
+    fputc('\n',stdout);
+#endif /* HAVE_GETPASS */
+
+  DBUG_RETURN(my_strdup(buff,MYF(MY_FAE)));
+}
+
+#ifndef HAVE_GETPASS
+/*
+** Can't use fgets, because readline will get confused
+** length is max number of chars in to, not counting \0
+*  to will not include the eol characters.
+*/
+
+void get_password(char *to,uint length,int fd,bool echo)
+{
+  char *pos=to,*end=to+length;
+
+  for (;;)
+  {
+    char tmp;
+    if (my_read(fd,&tmp,1,MYF(0)) != 1)
+      break;
+    if (tmp == '\b' || (int) tmp == 127)
+    {
+      if (pos != to)
+      {
+       if (echo)
+       {
+         fputs("\b \b",stdout);
+         fflush(stdout);
+       }
+       pos--;
+       continue;
+      }
+    }
+    if (tmp == '\n' || tmp == '\r' || tmp == 3)
+      break;
+    if (iscntrl(tmp) || pos == end)
+      continue;
+    if (echo)
+    {
+      fputc('*',stdout);
+      fflush(stdout);
+    }
+    *(pos++) = tmp;
+  }
+  while (pos != to && isspace(pos[-1]) == ' ')
+    pos--;                                     /* Allow dummy space at end */
+  *pos=0;
+  return;
+}
+#endif /* ! HAVE_GETPASS */
+
+#endif /*__WIN32__*/
diff --git a/ext/mysql/libmysql/libmysql.c b/ext/mysql/libmysql/libmysql.c
new file mode 100644 (file)
index 0000000..6be7bd7
--- /dev/null
@@ -0,0 +1,2361 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+   This file is public domain and comes with NO WARRANTY of any kind */
+
+#define DONT_USE_RAID
+#if defined(__WIN32__) || defined(WIN32)
+#include <winsock.h>
+#include <odbcinst.h>
+#endif
+#include <global.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>
+#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>
+#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(__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 | CLIENT_LOCAL_FILES)
+
+#if defined(MSDOS) || defined(__WIN32__)
+#define ERRNO WSAGetLastError()
+#define perror(A)
+#else
+#include <sys/errno.h>
+#define ERRNO errno
+#define SOCKET_ERROR -1
+#define closesocket(A) close(A)
+#endif
+
+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 remember_connection(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);
+
+/*
+  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(__WIN32__) && defined(SIGPIPE) && !defined(THREAD)
+#define init_sigpipe_variables  sig_return old_signal_handler;
+#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(File s, const struct sockaddr *name, uint namelen, uint to)
+{
+#if defined(__WIN32__)
+  return connect(s, (struct sockaddr*) name, namelen);
+#else
+  int flags, res, s_err;
+  size_socket 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;
+  res = select(s+1, NULL, &sfds, NULL, &tv);
+  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 suceed */
+    errno = s_err;
+    return(-1);                                        /* but return an error... */
+  }
+  return(0);                                   /* It's all good! */
+#endif
+}
+
+/*
+** Create a named pipe connection
+*/
+
+#ifdef __WIN32__
+
+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;
+      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
+*****************************************************************************/
+
+static uint
+net_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=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 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 (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_ulonglong
+net_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);
+    my_free((gptr) cur,MYF(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;
+  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;
+  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));
+      reset_sigpipe(mysql);
+      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;
+}
+
+
+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;
+}
+
+#ifdef HAVE_GETPWUID
+struct passwd *getpwuid(uid_t);
+char* getlogin(void);
+#endif
+
+#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;
+    const char *str;
+/*#ifdef __cplusplus
+    extern "C" struct passwd *getpwuid(uid_t);
+    extern "C" { char* getlogin(void); }
+#else
+    char * getlogin();
+    struct passwd *getpwuid(uid_t);
+#endif
+*/
+    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");
+  strmov(name,str ? str : "ODBC");      /* ODBC will send user variable */
+}
+
+#endif
+
+#ifdef __WIN32__
+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
+*/
+
+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(const 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_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
+**************************************************************************/
+
+static 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 were read; Ignoring rows"));
+      for (;;)
+      {
+       uint pkt_len;
+       if ((pkt_len=(uint) 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;
+    }
+    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;
+}
+
+
+/****************************************************************************
+** 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",
+#ifdef HAVE_OPENSSL
+ "ssl_key" ,"ssl_cert" ,"ssl_ca" ,"ssl_capath",
+#endif /* HAVE_OPENSSL */
+ NullS
+};
+static TYPELIB option_types={array_elements(default_options)-1,(char*) "options",(char **) default_options};
+
+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 '=' */
+       }
+       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;
+         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:                         /* pipe */
+         options->named_pipe=1;        /* Force named pipe */
+         break;
+       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 */
+         if (opt_arg)
+         {
+           my_free(options->init_command,MYF(MY_ALLOW_ZERO_PTR));
+           options->init_command=my_strdup(opt_arg,MYF(MY_WME));
+         }
+         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;
+#endif /* HAVE_OPENSSL */
+       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, 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->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))))
+    {
+      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=net_safe_read(mysql)) == packet_error)
+    {
+      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
+read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
+{
+  uint field;
+  ulong pkt_len,len;
+  uchar *pos,*prev_pos;
+
+  if ((pkt_len=(uint) 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;
+}
+
+/****************************************************************************
+** 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;
+    mysql->net.vio = 0;
+  }
+  else
+    bzero((char*) (mysql),sizeof(*(mysql)));
+#ifdef __WIN32__
+  mysql->options.connect_timeout=20;
+#endif
+  return mysql;
+}
+
+
+static void mysql_once_init()
+{
+  if (!mysql_client_init)
+  {
+    mysql_client_init=1;
+    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 __WIN32__
+      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)
+    (void) signal(SIGPIPE,SIG_IGN);
+#endif
+  }
+#ifdef THREAD
+  else
+    my_thread_init();         /* Init if new thread */
+#endif
+}
+
+#ifdef HAVE_OPENSSL
+/**************************************************************************
+** Fill in SSL part of MYSQL structure and set 'use_ssl' flag.
+** NB! Errors are not reported until you do mysql_real_connect.
+**************************************************************************/
+
+int STDCALL
+mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert,
+              const char *ca, const char *capath)
+{
+  mysql->options.ssl_key = key==0 ? 0 : my_strdup(key,MYF(0));
+  mysql->options.ssl_cert = cert==0 ? 0 : my_strdup(cert,MYF(0));
+  mysql->options.ssl_ca = ca==0 ? 0 : my_strdup(ca,MYF(0));
+  mysql->options.ssl_capath = capath==0 ? 0 : my_strdup(capath,MYF(0));
+  mysql->options.use_ssl = true;
+  mysql->connector_fd = new_VioSSLConnectorFd(key, cert, ca, capath);
+  return 0;
+}
+
+/**************************************************************************
+**************************************************************************/
+
+char * STDCALL
+mysql_ssl_cipher(MYSQL *mysql)
+{
+  return (char *)mysql->net.vio->cipher_description();
+}
+
+
+/**************************************************************************
+** Free strings in the SSL structure and clear 'use_ssl' flag.
+** NB! Errors are not reported until you do mysql_real_connect.
+**************************************************************************/
+
+int STDCALL
+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));
+  mysql->options.ssl_key = 0;
+  mysql->options.ssl_cert = 0;
+  mysql->options.ssl_ca = 0;
+  mysql->options.ssl_capath = 0;
+  mysql->options.use_ssl = false;
+  delete reinterpret_cast<VioConnectorFd*>(mysql->connector_fd);
+  mysql->connector_fd = 0;
+  return 0;
+}
+#endif /* HAVE_OPENSSL */
+
+/**************************************************************************
+** Connect to sql server
+** If host == 0 then use localhost
+**************************************************************************/
+
+MYSQL * STDCALL
+mysql_connect(MYSQL *mysql,const char *host,
+             const char *user, const char *passwd)
+{
+  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);
+  }
+}
+
+
+/*
+** 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,uint client_flag)
+{
+  char         buff[100],*end,*host_info;
+  int          sock;
+  ulong                ip_addr;
+  struct       sockaddr_in sock_addr;
+  uint         pkt_length;
+  NET          *net;
+#ifdef __WIN32__
+  HANDLE       hPipe=INVALID_HANDLE_VALUE;
+#endif
+#ifdef HAVE_SYS_UN_H
+  struct       sockaddr_un UNIXaddr;
+#endif
+  init_sigpipe_variables
+  DBUG_ENTER("mysql_real_connect");
+
+  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);
+  /* 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 (haneke) */
+#endif
+  }
+  if (!db || !db[0])
+    db=mysql->options.db;
+  if (!port)
+    port=mysql->options.port;
+  if (!unix_socket)
+    unix_socket=mysql->options.unix_socket;
+
+  remember_connection(mysql);
+  mysql->reconnect=1;                  /* Reconnect as default */
+  net= &mysql->net;
+  net->vio = 0;                                /* If something goes wrong */
+
+  /*
+  ** Grab a socket and connect it to the server
+  */
+
+#if defined(HAVE_SYS_UN_H)
+  if ((!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;
+      sprintf(net->last_error,ER(net->last_errno),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 (connect2(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
+                mysql->options.connect_timeout) <0)
+    {
+      DBUG_PRINT("error",("Got error %d on connect to local server",ERRNO));
+      net->last_errno=CR_CONNECTION_ERROR;
+      sprintf(net->last_error,ER(net->last_errno),unix_socket,ERRNO);
+      goto error;
+    }
+  }
+  else
+#elif defined(__WIN32__)
+  {
+    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 (!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));
+    if ((sock = socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
+    {
+      net->last_errno=CR_IPSOCK_ERROR;
+      sprintf(net->last_error,ER(net->last_errno),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(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr));
+    }
+    else
+#if defined(HAVE_GETHOSTBYNAME_R) && defined(_REENTRANT) && defined(THREAD)
+    {
+      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);
+       goto error;
+      }
+      memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+    }
+#else
+    {
+      struct hostent *hp;
+      if (!(hp=gethostbyname(host)))
+      {
+       net->last_errno=CR_UNKNOWN_HOST;
+       sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, errno);
+       goto error;
+      }
+      memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+    }
+#endif
+    sock_addr.sin_port = (ushort) htons((ushort) port);
+    if (connect2(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
+                mysql->options.connect_timeout) <0)
+    {
+      DBUG_PRINT("error",("Got error %d on connect to '%s'",ERRNO,host));
+      net->last_errno= CR_CONN_HOST_ERROR;
+      sprintf(net->last_error ,ER(CR_CONN_HOST_ERROR), host, ERRNO);
+      goto error;
+    }
+  }
+
+  if (!net->vio || my_net_init(net, net->vio))
+  {
+    vio_delete(net->vio);
+    net->last_errno=CR_OUT_OF_MEMORY;
+    strmov(net->last_error,ER(net->last_errno));
+    goto error;
+  }
+  vio_keepalive(net->vio,TRUE);
+
+  /* Get version info */
+  mysql->protocol_version= PROTOCOL_VERSION;   /* Assume this */
+  if ((pkt_length=net_safe_read(mysql)) == packet_error)
+    goto error;
+
+  /* Check if version of protocoll 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);
+  if (pkt_length > (uint) (end+9 - (char*) net->read_pos))
+    mysql->server_capabilities=uint2korr(end+9);
+
+  /* Save connection information */
+  if (!user) user="";
+  if (!passwd) passwd="";
+  if (!my_multi_malloc(MYF(0),
+                      &mysql->host_info,strlen(host_info)+1,
+                      &mysql->host,strlen(host)+1,
+                      &mysql->unix_socket,unix_socket ? strlen(unix_socket)+1
+                      :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;
+  mysql->client_flag=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.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))
+      goto error;
+    /* Do the SSL layering. */
+    DBUG_PRINT("info", ("IO layer change in progress..."));
+    VioSSLConnectorFd* connector_fd = (VioSSLConnectorFd*)
+      (mysql->connector_fd);
+    VioSocket* vio_socket = (VioSocket*)(mysql->net.vio);
+    VioSSL*    vio_ssl =    connector_fd->connect(vio_socket);
+    mysql->net.vio =         (NetVio*)(vio_ssl);
+  }
+#endif /* HAVE_OPENSSL */
+
+  int3store(buff+2,max_allowed_packet);
+  if (user && user[0])
+    strmake(buff+5,user,32);
+  else
+    read_user_name((char*) buff+5);
+  DBUG_PRINT("info",("user: %s",buff+5));
+  end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
+              (my_bool) (mysql->protocol_version == 9));
+  if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
+  {
+    end=strmov(end+1,db);
+    mysql->db=my_strdup(db,MYF(MY_WME));
+    db=0;
+  }
+  if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net) ||
+      net_safe_read(mysql) == packet_error)
+    goto error;
+  if (client_flag & CLIENT_COMPRESS)           /* We will use compression */
+    net->compress=1;
+  if (db && mysql_select_db(mysql,db))
+    goto error;
+  if (mysql->options.init_command)
+  {
+    my_bool reconnect=mysql->reconnect;
+    mysql->reconnect=0;
+    if (mysql_query(mysql,mysql->options.init_command))
+      goto error;
+    mysql_free_result(mysql_use_result(mysql));
+    mysql->reconnect=reconnect;
+  }
+
+  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);
+}
+
+
+static my_bool mysql_reconnect(MYSQL *mysql)
+{
+  MYSQL tmp_mysql;
+  DBUG_ENTER("mysql_reconnect");
+
+  if (!mysql->reconnect || !mysql->host_info)
+    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);
+  memcpy(mysql,&tmp_mysql,sizeof(tmp_mysql));
+  net_clear(&mysql->net);
+  mysql->affected_rows= ~(my_ulonglong) 0;
+  DBUG_RETURN(0);
+}
+
+
+/**************************************************************************
+** Change user and database 
+**************************************************************************/
+
+my_bool        STDCALL mysql_change_user(MYSQL *mysql, const char *user, 
+                                 const char *passwd, const char *db)
+{
+  char buff[512],*pos=buff;
+  DBUG_ENTER("mysql_change_user");
+
+  if (!user)
+    user="";
+  if (!passwd)
+    passwd="";
+
+  pos=strmov(pos,user)+1;
+  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))
+    DBUG_RETURN(1);
+
+  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));
+
+  mysql->user=  my_strdup(user,MYF(MY_WME));
+  mysql->passwd=my_strdup(passwd,MYF(MY_WME));
+  mysql->db=    db ? my_strdup(db,MYF(MY_WME)) : 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,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 */
+      simple_command(mysql,COM_QUIT,NullS,0,1);
+      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));
+    my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR));
+    my_free(mysql->options.user,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));
+    /* Clear pointers for better safety */
+    mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
+    bzero((char*) &mysql->options,sizeof(mysql->options));
+    mysql->net.vio = 0;
+#ifdef HAVE_OPENSSL
+    ((VioConnectorFd*)(mysql->connector_fd))->delete();
+    mysql->connector_fd = 0;
+#endif /* HAVE_OPENSSL */
+    if (mysql->free_me)
+      my_free((gptr) mysql,MYF(0));
+  }
+  DBUG_VOID_RETURN;
+}
+
+
+/**************************************************************************
+** Do a query. If query returned rows, free old rows.
+** Read data by mysql_store_result or by repeat call of mysql_fetch_row
+**************************************************************************/
+
+int STDCALL
+mysql_query(MYSQL *mysql, const char *query)
+{
+  return mysql_real_query(mysql,query,strlen(query));
+}
+
+
+int STDCALL
+mysql_real_query(MYSQL *mysql, const char *query,uint length)
+{
+  uchar *pos;
+  ulong field_count;
+  MYSQL_DATA *fields;
+  DBUG_ENTER("mysql_real_query");
+  DBUG_PRINT("enter",("handle: %lx",mysql));
+  DBUG_PRINT("query",("Query = \"%s\"",query));
+
+  if (simple_command(mysql,COM_QUERY,query,length,1) ||
+      (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 (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 */
+  }
+  mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
+  if (!(fields=read_rows(mysql,(MYSQL_FIELD*) 0,5)))
+    DBUG_RETURN(-1);
+  if (!(mysql->fields=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);
+}
+
+
+static int
+send_file_to_server(MYSQL *mysql, const char *filename)
+{
+  int fd, readcount;
+  char buf[IO_SIZE*15],*tmp_name;
+  DBUG_ENTER("send_file_to_server");
+
+  fn_format(buf,filename,"","",4);             /* Convert to client format */
+  if (!(tmp_name=my_strdup(buf,MYF(0))))
+  {
+    strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY));
+    DBUG_RETURN(-1);
+  }
+  if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0)
+  {
+    mysql->net.last_errno=EE_FILENOTFOUND;
+    sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno);
+    strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1);
+    my_net_write(&mysql->net,"",0); net_flush(&mysql->net);
+    my_free(tmp_name,MYF(0));
+    DBUG_RETURN(-1);
+  }
+
+  while ((readcount = (int) my_read(fd,buf,sizeof(buf),MYF(0))) > 0)
+  {
+    if (my_net_write(&mysql->net,buf,readcount))
+    {
+      mysql->net.last_errno=CR_SERVER_LOST;
+      strmov(mysql->net.last_error,ER(mysql->net.last_errno));
+      DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file"));
+      (void) my_close(fd,MYF(0));
+      my_free(tmp_name,MYF(0));
+      DBUG_RETURN(-1);
+    }
+  }
+  (void) my_close(fd,MYF(0));
+  /* 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);
+    my_free(tmp_name,MYF(0));
+    DBUG_RETURN(-1);
+  }
+  if (readcount < 0)
+  {
+    mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */
+    sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno);
+    strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1);
+    my_free(tmp_name,MYF(0));
+    DBUG_RETURN(-1);
+  }
+  DBUG_RETURN(0);
+}
+
+
+/**************************************************************************
+** Alloc result struct for buffered results. All rows are read to buffer.
+** mysql_data_seek may be used.
+**************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_store_result(MYSQL *mysql)
+{
+  MYSQL_RES *result;
+  DBUG_ENTER("mysql_store_result");
+
+  if (!mysql->fields)
+    DBUG_RETURN(0);
+  if (mysql->status != MYSQL_STATUS_GET_RESULT)
+  {
+    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_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 */
+}
+
+
+/**************************************************************************
+** Alloc struct for use with unbuffered reads. Data is fetched by domand
+** when calling to mysql_fetch_row.
+** mysql_data_seek is a noop.
+**
+** No other queries may be specified with the same MYSQL handle.
+** There shouldn't be much processing per row because mysql server shouldn't
+** have to wait for the client (and will not wait more than 30 sec/packet).
+**************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_use_result(MYSQL *mysql)
+{
+  MYSQL_RES *result;
+  DBUG_ENTER("mysql_use_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);
+  }
+  if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
+                                     sizeof(ulong)*mysql->field_count,
+                                     MYF(MY_WME | MY_ZEROFILL))))
+    DBUG_RETURN(0);
+  result->lengths=(ulong*) (result+1);
+  if (!(result->row=(MYSQL_ROW)
+       my_malloc(sizeof(result->row[0])*(mysql->field_count+1), MYF(MY_WME))))
+  {                                    /* Ptrs: to one row */
+    my_free((gptr) result,MYF(0));
+    DBUG_RETURN(0);
+  }
+  result->fields=      mysql->fields;
+  result->field_alloc= mysql->field_alloc;
+  result->field_count= mysql->field_count;
+  result->current_field=0;
+  result->handle=      mysql;
+  result->current_row= 0;
+  mysql->fields=0;                     /* fields is now in result */
+  mysql->status=MYSQL_STATUS_USE_RESULT;
+  DBUG_RETURN(result);                 /* Data is read to be fetched */
+}
+
+
+
+/**************************************************************************
+** Return next field of the query results
+**************************************************************************/
+
+MYSQL_FIELD * STDCALL
+mysql_fetch_field(MYSQL_RES *result)
+{
+  if (result->current_field >= result->field_count)
+    return(NULL);
+  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
+      {
+       res->eof=1;
+       res->handle->status=MYSQL_STATUS_READY;
+      }
+    }
+    DBUG_RETURN((MYSQL_ROW) NULL);
+  }
+  {
+    MYSQL_ROW tmp;
+    if (!res->data_cursor)
+      DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
+    tmp = res->data_cursor->data;
+    res->data_cursor = res->data_cursor->next;
+    DBUG_RETURN(res->current_row=tmp);
+  }
+}
+
+/**************************************************************************
+** Get column lengths of the current row
+** If one uses mysql_use_result, res->lengths contains the length information,
+** else the lengths are calculated from the offset between pointers.
+**************************************************************************/
+
+ulong * STDCALL
+mysql_fetch_lengths(MYSQL_RES *res)
+{
+  ulong *lengths,*prev_length;
+  byte *start;
+  MYSQL_ROW column,end;
+
+  if (!(column=res->current_row))
+    return 0;                                  /* Something is wrong */
+  if (res->data)
+  {
+    start=0;
+    prev_length=0;                             /* Keep gcc happy */
+    lengths=res->lengths;
+    for (end=column+res->field_count+1 ; column != end ; column++,lengths++)
+    {
+      if (!*column)
+      {
+       *lengths=0;                             /* Null */
+       continue;
+      }
+      if (start)                               /* Found end of prev string */
+       *prev_length= (uint) (*column-start-1);
+      start= *column;
+      prev_length=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(%d)",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()
+** This dosen't restore any data. The next mysql_fetch_row or
+** mysql_fetch_field will return the next row or field after the last used
+*************************************************************************/
+
+MYSQL_ROW_OFFSET STDCALL
+mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET row)
+{
+  MYSQL_ROW_OFFSET return_value=result->data_cursor;
+  result->current_row= 0;
+  result->data_cursor= row;
+  return return_value;
+}
+
+
+MYSQL_FIELD_OFFSET STDCALL
+mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET field_offset)
+{
+  MYSQL_FIELD_OFFSET return_value=result->current_field;
+  result->current_field=field_offset;
+  return return_value;
+}
+
+/*****************************************************************************
+** List all databases
+*****************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_list_dbs(MYSQL *mysql, const char *wild)
+{
+  char buff[255];
+  DBUG_ENTER("mysql_list_dbs");
+
+  append_wild(strmov(buff,"show databases"),buff+sizeof(buff),wild);
+  if (mysql_query(mysql,buff))
+    DBUG_RETURN(0);
+  DBUG_RETURN (mysql_store_result(mysql));
+}
+
+
+/*****************************************************************************
+** List all tables in a database
+** If wild is given then only the tables matching wild is returned
+*****************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_list_tables(MYSQL *mysql, const char *wild)
+{
+  char buff[255];
+  DBUG_ENTER("mysql_list_tables");
+
+  append_wild(strmov(buff,"show tables"),buff+sizeof(buff),wild);
+  if (mysql_query(mysql,buff))
+    DBUG_RETURN(0);
+  DBUG_RETURN (mysql_store_result(mysql));
+}
+
+
+/**************************************************************************
+** List all fields in a table
+** If wild is given then only the fields matching wild is returned
+** Instead of this use query:
+** show fields in 'table' like "wild"
+**************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
+{
+  MYSQL_RES *result;
+  MYSQL_DATA *query;
+  char      buff[257],*end;
+  DBUG_ENTER("mysql_list_fields");
+  DBUG_PRINT("enter",("table: '%s'  wild: '%s'",table,wild ? wild : ""));
+
+  LINT_INIT(query);
+
+  end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128);
+  if (simple_command(mysql,COM_FIELD_LIST,buff,(uint) (end-buff),1) ||
+      !(query = read_rows(mysql,(MYSQL_FIELD*) 0,6)))
+    DBUG_RETURN(NULL);
+
+  free_old_query(mysql);
+  if (!(result = (MYSQL_RES *) my_malloc(sizeof(MYSQL_RES),
+                                        MYF(MY_WME | MY_ZEROFILL))))
+  {
+    free_rows(query);
+    DBUG_RETURN(NULL);
+  }
+  result->field_alloc=mysql->field_alloc;
+  mysql->fields=0;
+  result->field_count = (uint) query->rows;
+  result->fields= unpack_fields(query,&result->field_alloc,
+                               result->field_count,1,
+                               (my_bool) test(mysql->server_capabilities &
+                                              CLIENT_LONG_FLAG));
+  result->eof=1;
+  DBUG_RETURN(result);
+}
+
+/* List all running processes (threads) in server */
+
+MYSQL_RES * STDCALL
+mysql_list_processes(MYSQL *mysql)
+{
+  MYSQL_DATA *fields;
+  uint field_count;
+  uchar *pos;
+  DBUG_ENTER("mysql_list_processes");
+
+  LINT_INIT(fields);
+  if (simple_command(mysql,COM_PROCESS_INFO,0,0,0))
+    DBUG_RETURN(0);
+  free_old_query(mysql);
+  pos=(uchar*) mysql->net.read_pos;
+  field_count=(uint) net_field_length(&pos);
+  if (!(fields = read_rows(mysql,(MYSQL_FIELD*) 0,5)))
+    DBUG_RETURN(NULL);
+  if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0,
+                                   (my_bool) test(mysql->server_capabilities &
+                                                  CLIENT_LONG_FLAG))))
+    DBUG_RETURN(0);
+  mysql->status=MYSQL_STATUS_GET_RESULT;
+  mysql->field_count=field_count;
+  DBUG_RETURN(mysql_store_result(mysql));
+}
+
+
+int  STDCALL
+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));
+}
+
+
+int  STDCALL
+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));
+}
+
+
+int STDCALL
+mysql_shutdown(MYSQL *mysql)
+{
+  DBUG_ENTER("mysql_shutdown");
+  DBUG_RETURN(simple_command(mysql,COM_SHUTDOWN,0,0,0));
+}
+
+
+int STDCALL
+mysql_refresh(MYSQL *mysql,uint options)
+{
+  uchar bits[1];
+  DBUG_ENTER("mysql_refresh");
+  bits[0]= (uchar) options;
+  DBUG_RETURN(simple_command(mysql,COM_REFRESH,(char*) bits,1,0));
+}
+
+int STDCALL
+mysql_kill(MYSQL *mysql,ulong pid)
+{
+  char buff[12];
+  DBUG_ENTER("mysql_kill");
+  int4store(buff,pid);
+  DBUG_RETURN(simple_command(mysql,COM_PROCESS_KILL,buff,4,0));
+}
+
+
+int STDCALL
+mysql_dump_debug_info(MYSQL *mysql)
+{
+  DBUG_ENTER("mysql_dump_debug_info");
+  DBUG_RETURN(simple_command(mysql,COM_DEBUG,0,0,0));
+}
+
+char * STDCALL
+mysql_stat(MYSQL *mysql)
+{
+  DBUG_ENTER("mysql_stat");
+  if (simple_command(mysql,COM_STATISTICS,0,0,0))
+    return mysql->net.last_error;
+  mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
+  if (!mysql->net.read_pos[0])
+  {
+    mysql->net.last_errno=CR_WRONG_HOST_INFO;
+    strmov(mysql->net.last_error, ER(mysql->net.last_errno));
+    return mysql->net.last_error;
+  }
+  DBUG_RETURN((char*) mysql->net.read_pos);
+}
+
+
+int STDCALL
+mysql_ping(MYSQL *mysql)
+{
+  DBUG_ENTER("mysql_ping");
+  DBUG_RETURN(simple_command(mysql,COM_PING,0,0,0));
+}
+
+
+char * STDCALL
+mysql_get_server_info(MYSQL *mysql)
+{
+  return((char*) mysql->server_version);
+}
+
+
+char * STDCALL
+mysql_get_host_info(MYSQL *mysql)
+{
+  return(mysql->host_info);
+}
+
+
+uint STDCALL
+mysql_get_proto_info(MYSQL *mysql)
+{
+  return (mysql->protocol_version);
+}
+
+char * STDCALL
+mysql_get_client_info(void)
+{
+  return (char*) MYSQL_SERVER_VERSION;
+}
+
+
+int STDCALL
+mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
+{
+  DBUG_ENTER("mysql_option");
+  DBUG_PRINT("enter",("option: %d",(int) option));
+  switch (option) {
+  case MYSQL_OPT_CONNECT_TIMEOUT:
+    mysql->options.connect_timeout= *(uint*) arg;
+    break;
+  case MYSQL_OPT_COMPRESS:
+    mysql->options.compress=1;                 /* Remember for connect */
+    break;
+  case MYSQL_OPT_NAMED_PIPE:
+    mysql->options.named_pipe=1;               /* Force named pipe */
+    break;
+  case MYSQL_INIT_COMMAND:
+    my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR));
+    mysql->options.init_command=my_strdup(arg,MYF(MY_WME));
+    break;
+  case MYSQL_READ_DEFAULT_FILE:
+    my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+    mysql->options.my_cnf_file=my_strdup(arg,MYF(MY_WME));
+    break;
+  case MYSQL_READ_DEFAULT_GROUP:
+    my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+    mysql->options.my_cnf_group=my_strdup(arg,MYF(MY_WME));
+    break;
+  default:
+    DBUG_RETURN(-1);
+  }
+  DBUG_RETURN(0);
+}
+
+/****************************************************************************
+** Functions to get information from the MySQL structure
+** These are functions to make shared libraries more usable.
+****************************************************************************/
+
+/* MYSQL_RES */
+my_ulonglong mysql_num_rows(MYSQL_RES *res)
+{
+  return res->row_count;
+}
+
+unsigned int mysql_num_fields(MYSQL_RES *res)
+{
+  return res->field_count;
+}
+
+my_bool mysql_eof(MYSQL_RES *res)
+{
+  return res->eof;
+}
+
+MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr)
+{
+  return &(res)->fields[fieldnr];
+}
+
+MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res)
+{
+  return (res)->fields;
+}
+
+MYSQL_ROWS *mysql_row_tell(MYSQL_RES *res)
+{
+  return res->data_cursor;
+}
+
+uint mysql_field_tell(MYSQL_RES *res)
+{
+  return (res)->current_field;
+}
+
+/* MYSQL */
+
+unsigned int mysql_field_count(MYSQL *mysql)
+{
+  return mysql->field_count;
+}
+
+my_ulonglong mysql_affected_rows(MYSQL *mysql)
+{
+  return (mysql)->affected_rows;
+}
+
+my_ulonglong mysql_insert_id(MYSQL *mysql)
+{
+  return (mysql)->insert_id;
+}
+
+uint mysql_errno(MYSQL *mysql)
+{
+  return (mysql)->net.last_errno;
+}
+
+char *mysql_error(MYSQL *mysql)
+{
+  return (mysql)->net.last_error;
+}
+
+char *mysql_info(MYSQL *mysql)
+{
+  return (mysql)->info;
+}
+
+ulong mysql_thread_id(MYSQL *mysql)
+{
+  return (mysql)->thread_id;
+}
+
+/****************************************************************************
+** Some support functions
+****************************************************************************/
+
+/*
+** Add escape characters to a string (blob?) to make it suitable for a insert
+** to should at least have place for length*2+1 chars
+** Returns the length of the to string
+*/
+
+ulong STDCALL
+mysql_escape_string(char *to,const char *from,ulong length)
+{
+  const char *to_start=to;
+  const char *end;
+  for (end=from+length; from != end ; from++)
+  {
+#ifdef USE_MB
+    int l;
+    if ((l = ismbchar(from, end)))
+    {
+      while (l--)
+         *to++ = *from++;
+      from--;
+      continue;
+    }
+#endif
+    switch (*from) {
+    case 0:                            /* Must be escaped for 'mysql' */
+      *to++= '\\';
+      *to++= '0';
+      break;
+    case '\n':                         /* Must be escaped for logs */
+      *to++= '\\';
+      *to++= 'n';
+      break;
+    case '\r':
+      *to++= '\\';
+      *to++= 'r';
+      break;
+    case '\\':
+      *to++= '\\';
+      *to++= '\\';
+      break;
+    case '\'':
+      *to++= '\\';
+      *to++= '\'';
+      break;
+    case '"':                          /* Better safe than sorry */
+      *to++= '\\';
+      *to++= '"';
+      break;
+    case '\032':                       /* This gives problems on Win32 */
+      *to++= '\\';
+      *to++= 'Z';
+      break;
+    default:
+      *to++= *from;
+    }
+  }
+  *to=0;
+  return (ulong) (to-to_start);
+}
+
+
+char * STDCALL
+mysql_odbc_escape_string(char *to, ulong to_length,
+                        const char *from, ulong from_length,
+                        void *param,
+                        char * (*extend_buffer)
+                        (void *, char *, ulong *))
+{
+  char *to_end=to+to_length-5;
+  const char *end;
+
+  for (end=from+from_length; from != end ; from++)
+  {
+    if (to >= to_end)
+    {
+      to_length = (ulong) (end-from)+512;      /* We want this much more */
+      if (!(to=(*extend_buffer)(param, to, &to_length)))
+       return to;
+      to_end=to+to_length-5;
+    }
+#ifdef USE_MB
+    {
+      int l;
+      if ((l = ismbchar(from, end)))
+      {
+       while (l--)
+         *to++ = *from++;
+       from--;
+       continue;
+      }
+    }
+#endif
+    switch (*from) {
+    case 0:                            /* Must be escaped for 'mysql' */
+      *to++= '\\';
+      *to++= '0';
+      break;
+    case '\n':                         /* Must be escaped for logs */
+      *to++= '\\';
+      *to++= 'n';
+      break;
+    case '\r':
+      *to++= '\\';
+      *to++= 'r';
+      break;
+    case '\\':
+      *to++= '\\';
+      *to++= '\\';
+      break;
+    case '\'':
+      *to++= '\\';
+      *to++= '\'';
+      break;
+    case '"':                          /* Better safe than sorry */
+      *to++= '\\';
+      *to++= '"';
+      break;
+    case '\032':                       /* This gives problems on Win32 */
+      *to++= '\\';
+      *to++= 'Z';
+      break;
+    default:
+      *to++= *from;
+    }
+  }
+  return to;
+}
diff --git a/ext/mysql/libmysql/net.c b/ext/mysql/libmysql/net.c
new file mode 100644 (file)
index 0000000..9af0a54
--- /dev/null
@@ -0,0 +1,606 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+   This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Write and read of logical packets to/from socket
+** Writes are cached into net_buffer_length big packets.
+** Read packets are reallocated dynamicly when reading big packets.
+** Each logical packet has the following pre-info:
+** 3 byte length & 1 byte package-number.
+*/
+
+#ifdef _WIN32
+#include <winsock.h>
+#endif
+#include <global.h>
+#include <violite.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <violite.h>
+
+#if !defined(__WIN32__) && !defined(MSDOS)
+#include <sys/socket.h>
+#endif
+#if !defined(MSDOS) && !defined(__WIN32__) && !defined(HAVE_BROKEN_NETINET_INCLUDES)
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#if !defined(alpha_linux_port)
+#include <netinet/tcp.h>
+#endif
+#endif
+#include "mysqld_error.h"
+#ifdef MYSQL_SERVER
+#include "my_pthread.h"
+#include "thr_alarm.h"
+void sql_print_error(const char *format,...);
+#define RETRY_COUNT mysqld_net_retry_count
+extern ulong mysqld_net_retry_count;
+#else
+typedef my_bool thr_alarm_t;
+#define thr_alarm_init(A) (*A)=0
+#define thr_alarm_in_use(A) (A)
+#define thr_end_alarm(A)
+#define thr_alarm(A,B) local_thr_alarm((A),(B))
+static inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)))
+{
+  *A=1;
+  return 0;
+}
+#define thr_got_alarm(A) 0
+#define RETRY_COUNT 1
+#endif
+
+#ifdef MYSQL_SERVER
+extern ulong bytes_sent, bytes_received; 
+extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
+#else
+#undef thread_safe_add
+#define thread_safe_add(A,B,C)
+#endif
+
+/*
+** Give error if a too big packet is found
+** The server can change this with the -O switch, but because the client
+** can't normally do this the client should have a bigger max-buffer.
+*/
+
+#ifdef MYSQL_SERVER
+ulong max_allowed_packet=65536;
+extern uint test_flags;
+#else
+ulong max_allowed_packet=24*1024*1024L;
+#endif
+ulong net_buffer_length=8192;  /* Default length. Enlarged if necessary */
+
+#define TEST_BLOCKING          8
+static int net_write_buff(NET *net,const char *packet,uint len);
+
+
+       /* Init with packet info */
+
+int my_net_init(NET *net, Vio* vio)
+{
+  if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME))))
+    return 1;
+  if (net_buffer_length > max_allowed_packet)
+    max_allowed_packet=net_buffer_length;
+  net->buff_end=net->buff+(net->max_packet=net_buffer_length);
+  net->vio = vio;
+  net->error=net->return_errno=0;
+  net->timeout=NET_READ_TIMEOUT;               /* Timeout for read */
+  net->pkt_nr=0;
+  net->write_pos=net->read_pos = net->buff;
+  net->last_error[0]=0;
+  net->compress=net->more=0;
+  net->where_b = net->remain_in_buf=0;
+  net->last_errno=0;
+
+  if (vio != 0)                                        /* If real connection */
+  {
+    net->fd  = vio_fd(vio);                    /* For perl DBI/DBD */
+#if defined(MYSQL_SERVER) && !defined(___WIN32__) && !defined(__EMX__)
+    if (!(test_flags & TEST_BLOCKING))
+      vio_blocking(vio, FALSE);
+#endif
+    vio_fastsend(vio,TRUE);
+  }
+  return 0;
+}
+
+void net_end(NET *net)
+{
+  my_free((gptr) net->buff,MYF(MY_ALLOW_ZERO_PTR));
+  net->buff=0;
+}
+
+/* Realloc the packet buffer */
+
+static my_bool net_realloc(NET *net, ulong length)
+{
+  uchar *buff;
+  ulong pkt_length;
+  if (length >= max_allowed_packet)
+  {
+    DBUG_PRINT("error",("Packet too large (%ld)", length));
+#ifdef MYSQL_SERVER
+    sql_print_error("Packet too large (%ld)\n", length);
+#else
+    fprintf(stderr,"Packet too large (%ld)\n", length);
+#endif
+    net->error=1;
+#ifdef MYSQL_SERVER
+    net->last_errno=ER_NET_PACKET_TOO_LARGE;
+#endif
+    return 1;
+  }
+  pkt_length = (length+IO_SIZE) & ~(IO_SIZE-1);
+  if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
+  {
+    net->error=1;
+#ifdef MYSQL_SERVER
+    net->last_errno=ER_OUT_OF_RESOURCES;
+#endif
+    return 1;
+  }
+  net->buff=net->write_pos=buff;
+  net->buff_end=buff+(net->max_packet=pkt_length);
+  return 0;
+}
+
+       /* Remove unwanted characters from connection */
+
+#ifndef MYSQL_SERVER
+void net_clear(NET *net)
+{
+#ifndef EXTRA_DEBUG
+  int count;
+  vio_blocking(net->vio, FALSE);
+  if (!vio_is_blocking(net->vio))              /* Safety if SSL */
+  {
+    while ( (count = vio_read(net->vio, (char*) (net->buff),
+                             net->max_packet)) > 0)
+      DBUG_PRINT("info",("skipped %d bytes from file: %s",
+                        count,vio_description(net->vio)));
+  }
+#endif /* EXTRA_DEBUG */
+  net->pkt_nr=0;                               /* Ready for new command */
+  net->write_pos=net->buff;
+}
+#endif /* MYSQL_SERVER */
+
+       /* Flush write_buffer if not empty. */
+
+int net_flush(NET *net)
+{
+  int error=0;
+  if (net->buff != net->write_pos)
+  {
+    error=net_real_write(net,(char*) net->buff,
+                        (uint) (net->write_pos - net->buff));
+    net->write_pos=net->buff;
+  }
+  return error;
+}
+
+
+/*****************************************************************************
+** Write something to server/client buffer
+*****************************************************************************/
+
+
+/*
+** Write a logical packet with packet header
+** Format: Packet length (3 bytes), packet number(1 byte)
+**         When compression is used a 3 byte compression length is added
+** NOTE: If compression is used the original package is destroyed!
+*/
+
+int
+my_net_write(NET *net,const char *packet,ulong len)
+{
+  uchar buff[NET_HEADER_SIZE];
+  int3store(buff,len);
+  buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+  if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
+    return 1;
+  return net_write_buff(net,packet,len);
+}
+
+int
+net_write_command(NET *net,uchar command,const char *packet,ulong len)
+{
+  uchar buff[NET_HEADER_SIZE+1];
+  uint length=len+1;                           /* 1 extra byte for command */
+
+  int3store(buff,length);
+  buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+  buff[4]=command;
+  if (net_write_buff(net,(char*) buff,5))
+    return 1;
+  return test(net_write_buff(net,packet,len) || net_flush(net));
+}
+
+
+static int
+net_write_buff(NET *net,const char *packet,uint len)
+{
+  uint left_length=(uint) (net->buff_end - net->write_pos);
+
+  while (len > left_length)
+  {
+    memcpy((char*) net->write_pos,packet,left_length);
+    if (net_real_write(net,(char*) net->buff,net->max_packet))
+      return 1;
+    net->write_pos=net->buff;
+    packet+=left_length;
+    len-=left_length;
+    left_length=net->max_packet;
+  }
+  memcpy((char*) net->write_pos,packet,len);
+  net->write_pos+=len;
+  return 0;
+}
+
+/*  Read and write using timeouts */
+
+int
+net_real_write(NET *net,const char *packet,ulong len)
+{
+  int length;
+  char *pos,*end;
+  thr_alarm_t alarmed;
+  uint retry_count=0;
+  my_bool net_blocking = vio_is_blocking(net->vio);
+
+#ifdef HAVE_COMPRESS
+  if (net->compress)
+  {
+    ulong complen;
+    uchar *b;
+    uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
+    if (!(b=(uchar*) my_malloc(len + NET_HEADER_SIZE + COMP_HEADER_SIZE,
+                                   MYF(MY_WME))))
+    {
+#ifdef MYSQL_SERVER
+      net->last_errno=ER_OUT_OF_RESOURCES;
+      net->error=1;
+#endif
+      return 1;
+    }
+    memcpy(b+header_length,packet,len);
+
+    if (my_compress((byte*) b+header_length,&len,&complen))
+    {
+      DBUG_PRINT("warning",
+                ("Compression error; Continuing without compression"));
+      complen=0;
+    }
+    int3store(&b[NET_HEADER_SIZE],complen);
+    int3store(b,len);
+    b[3]=(uchar) (net->pkt_nr++);
+    len+= header_length;
+    packet= (char*) b;
+  }
+#endif /* HAVE_COMPRESS */
+
+  /* DBUG_DUMP("net",packet,len); */
+#ifdef MYSQL_SERVER
+  thr_alarm_init(&alarmed);
+  if (net_blocking)
+    thr_alarm(&alarmed,NET_WRITE_TIMEOUT);
+#else
+  alarmed=0;
+#endif /* MYSQL_SERVER */
+
+  pos=(char*) packet; end=pos+len;
+  while (pos != end)
+  {
+    if ((int) (length=vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
+    {
+      my_bool interrupted = vio_should_retry(net->vio);
+#if (!defined(__WIN32__) && !defined(__EMX__))
+      if ((interrupted || length==0) && !thr_alarm_in_use(alarmed))
+      {
+        if (!thr_alarm(&alarmed,NET_WRITE_TIMEOUT))
+        {                                       /* Always true for client */
+         if (!vio_is_blocking(net->vio))
+         {
+           while (vio_blocking(net->vio, TRUE) < 0)
+           {
+             if (vio_should_retry(net->vio) && retry_count++ < RETRY_COUNT)
+               continue;
+#ifdef EXTRA_DEBUG
+             fprintf(stderr,
+                     "%s: my_net_write: fcntl returned error %d, aborting thread\n",
+                     my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+             net->error=1;                     /* Close socket */
+             goto end;
+           }
+         }
+         retry_count=0;
+         continue;
+       }
+      }
+      else
+#endif /* (!defined(__WIN32__) && !defined(__EMX__)) */
+       if (thr_alarm_in_use(alarmed) && !thr_got_alarm(alarmed) &&
+           interrupted)
+      {
+       if (retry_count++ < RETRY_COUNT)
+           continue;
+#ifdef EXTRA_DEBUG
+         fprintf(stderr, "%s: write looped, aborting thread\n",
+                 my_progname);
+#endif /* EXTRA_DEBUG */
+      }
+#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+      if (vio_errno(net->vio) == EINTR)
+      {
+       DBUG_PRINT("warning",("Interrupted write. Retrying..."));
+       continue;
+      }
+#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
+      net->error=1;                            /* Close socket */
+#ifdef MYSQL_SERVER
+      net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
+                       ER_NET_ERROR_ON_WRITE);
+#endif /* MYSQL_SERVER */
+      break;
+    }
+    pos+=length;
+    thread_safe_add(bytes_sent,length,&LOCK_bytes_sent);
+  }
+#ifndef __WIN32__
+ end:
+#endif
+#ifdef HAVE_COMPRESS
+  if (net->compress)
+    my_free((char*) packet,MYF(0));
+#endif
+  if (thr_alarm_in_use(alarmed))
+  {
+    thr_end_alarm(&alarmed);
+    vio_blocking(net->vio, net_blocking);
+  }
+  return (int) (pos != end);
+}
+
+
+/*****************************************************************************
+** Read something from server/clinet
+*****************************************************************************/
+
+
+static uint
+my_real_read(NET *net, ulong *complen)
+{
+  uchar *pos;
+  long length;
+  uint i,retry_count=0;
+  ulong len=packet_error;
+  thr_alarm_t alarmed;
+  my_bool net_blocking=vio_is_blocking(net->vio);
+  ulong remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
+                NET_HEADER_SIZE);
+  *complen = 0;
+
+  thr_alarm_init(&alarmed);
+#ifdef MYSQL_SERVER
+  if (net_blocking)
+    thr_alarm(&alarmed,net->timeout);
+#endif /* MYSQL_SERVER */
+
+    pos = net->buff + net->where_b;            /* net->packet -4 */
+    for (i=0 ; i < 2 ; i++)
+    {
+      while (remain > 0)
+      {
+       /* First read is done with non blocking mode */
+        if ((int) (length=vio_read(net->vio,(char*) pos,remain)) <= 0L)
+        {
+          my_bool interrupted = vio_should_retry(net->vio);
+
+         DBUG_PRINT("info",("vio_read returned %d,  errno: %d",
+                            length, vio_errno(net->vio)));
+#if (!defined(__WIN32__) && !defined(__EMX__)) || !defined(MYSQL_SERVER)
+         /*
+           We got an error that there was no data on the socket. We now set up
+           an alarm to not 'read forever', change the socket to non blocking
+           mode and try again
+         */
+         if ((interrupted || length == 0) && !thr_alarm_in_use(alarmed))
+         {
+           if (!thr_alarm(&alarmed,net->timeout)) /* Don't wait too long */
+           {
+              if (!vio_is_blocking(net->vio))
+              {
+                while (vio_blocking(net->vio,TRUE) < 0)
+                {
+                  if (vio_should_retry(net->vio) &&
+                     retry_count++ < RETRY_COUNT)
+                    continue;
+                  DBUG_PRINT("error",
+                            ("fcntl returned error %d, aborting thread",
+                             vio_errno(net->vio)));
+#ifdef EXTRA_DEBUG
+                  fprintf(stderr,
+                          "%s: read: fcntl returned error %d, aborting thread\n",
+                          my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+                  len= packet_error;
+                  net->error=1;                 /* Close socket */
+#ifdef MYSQL_SERVER
+                 net->last_errno=ER_NET_FCNTL_ERROR;
+#endif
+                 goto end;
+                }
+              }
+             retry_count=0;
+             continue;
+           }
+         }
+#endif /* (!defined(__WIN32__) && !defined(__EMX__)) || !defined(MYSQL_SERVER) */
+         if (thr_alarm_in_use(alarmed) && !thr_got_alarm(alarmed) &&
+             interrupted)
+         {                                     /* Probably in MIT threads */
+           if (retry_count++ < RETRY_COUNT)
+             continue;
+#ifdef EXTRA_DEBUG
+           fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
+                   my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+         }
+#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+         if (vio_should_retry(net->vio))
+         {
+           DBUG_PRINT("warning",("Interrupted read. Retrying..."));
+           continue;
+         }
+#endif
+         DBUG_PRINT("error",("Couldn't read packet: remain: %d  errno: %d  length: %d  alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
+         len= packet_error;
+         net->error=1;                         /* Close socket */
+#ifdef MYSQL_SERVER
+         net->last_errno= (interrupted ? ER_NET_READ_INTERRUPTED :
+                           ER_NET_READ_ERROR);
+#endif
+         goto end;
+       }
+       remain -= (ulong) length;
+       pos+= (ulong) length;
+       thread_safe_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+      }
+      if (i == 0)
+      {                                        /* First parts is packet length */
+       ulong helping;
+       if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
+       {
+         if (net->buff[net->where_b] != (uchar) 255)
+         {
+           DBUG_PRINT("error",
+                      ("Packets out of order (Found: %d, expected %d)",
+                       (int) net->buff[net->where_b + 3],
+                       (uint) (uchar) net->pkt_nr));
+#ifdef EXTRA_DEBUG
+           fprintf(stderr,"Packets out of order (Found: %d, expected %d)\n",
+                   (int) net->buff[net->where_b + 3],
+                   (uint) (uchar) net->pkt_nr);
+#endif
+         }
+         len= packet_error;
+#ifdef MYSQL_SERVER
+         net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
+#endif
+         goto end;
+       }
+       net->pkt_nr++;
+#ifdef HAVE_COMPRESS
+       if (net->compress)
+       {
+         /* complen is > 0 if package is really compressed */
+         *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
+       }
+#endif
+
+       len=uint3korr(net->buff+net->where_b);
+       helping = max(len,*complen) + net->where_b;
+       /* The necessary size of net->buff */
+       if (helping >= net->max_packet)
+       {
+         if (net_realloc(net,helping))
+         {
+           len= packet_error;          /* Return error */
+           goto end;
+         }
+       }
+       pos=net->buff + net->where_b;
+       remain = len;
+      }
+    }
+
+end:
+  if (thr_alarm_in_use(alarmed))
+  {
+    thr_end_alarm(&alarmed);
+    vio_blocking(net->vio, net_blocking);
+  }
+  return(len);
+}
+
+
+uint
+my_net_read(NET *net)
+{
+  ulong len,complen;
+
+#ifdef HAVE_COMPRESS
+  if (!net->compress)
+  {
+#endif
+    len = my_real_read (net,&complen);
+    net->read_pos = net->buff + net->where_b;
+    if (len != packet_error)
+      net->read_pos[len]=0;            /* Safeguard for mysql_use_result */
+    return len;
+#ifdef HAVE_COMPRESS
+  }
+  if (net->remain_in_buf)
+    net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
+  for (;;)
+  {
+    if (net->remain_in_buf)
+    {
+      uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
+      if (net->remain_in_buf >= 4)
+      {
+       net->length = uint3korr(pos);
+       if (net->length <= net->remain_in_buf - 4)
+       {
+         /* We have a full packet */
+         len=net->length;
+         net->remain_in_buf -= net->length + 4;
+         net->read_pos=pos + 4;
+         break;                        /* We have a full packet */
+       }
+      }
+      /* Move data down to read next data packet after current one */
+      if (net->buf_length != net->remain_in_buf)
+      {
+       memmove(net->buff,pos,net->remain_in_buf);
+       net->buf_length=net->remain_in_buf;
+      }
+      net->where_b=net->buf_length;
+    }
+    else
+    {
+      net->where_b=0;
+      net->buf_length=0;
+    }
+
+    if ((len = my_real_read(net,&complen)) == packet_error)
+      break;
+    if (my_uncompress((byte*) net->buff + net->where_b, &len, &complen))
+    {
+      len= packet_error;
+      net->error=1;                    /* caller will close socket */
+#ifdef MYSQL_SERVER
+      net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+#endif
+      break;
+    }
+    net->buf_length+=len;
+    net->remain_in_buf+=len;
+  }
+  if (len != packet_error)
+  {
+    net->save_char= net->read_pos[len];        /* Must be saved */
+    net->read_pos[len]=0;              /* Safeguard for mysql_use_result */
+  }
+  return len;
+#endif
+}
diff --git a/ext/mysql/libmysql/password.c b/ext/mysql/libmysql/password.c
new file mode 100644 (file)
index 0000000..4666799
--- /dev/null
@@ -0,0 +1,178 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+   This file is public domain and comes with NO WARRANTY of any kind */
+
+/* password checking routines */
+/*****************************************************************************
+  The main idea is that no password are sent between client & server on
+  connection and that no password are saved in mysql in a decodable form.
+
+  On connection a random string is generated and sent to the client.
+  The client generates a new string with a random generator inited with
+  the hash values from the password and the sent string.
+  This 'check' string is sent to the server where it is compared with
+  a string generated from the stored hash_value of the password and the
+  random string.
+
+  The password is saved (in user.password) by using the PASSWORD() function in
+  mysql.
+
+  Example:
+    update user set password=PASSWORD("hello") where user="test"
+  This saves a hashed number as a string in the password field.
+*****************************************************************************/
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+
+
+void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
+{                                              /* For mysql 3.21.# */
+#ifdef HAVE_purify
+  bzero((char*) rand_st,sizeof(*rand_st));             /* Avoid UMC varnings */
+#endif
+  rand_st->max_value= 0x3FFFFFFFL;
+  rand_st->max_value_dbl=(double) rand_st->max_value;
+  rand_st->seed1=seed1%rand_st->max_value ;
+  rand_st->seed2=seed2%rand_st->max_value;
+}
+
+static void old_randominit(struct rand_struct *rand_st,ulong seed1)
+{                                              /* For mysql 3.20.# */
+  rand_st->max_value= 0x01FFFFFFL;
+  rand_st->max_value_dbl=(double) rand_st->max_value;
+  seed1%=rand_st->max_value;
+  rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
+}
+
+double rnd(struct rand_struct *rand_st)
+{
+  rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
+  rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
+  return (((double) rand_st->seed1)/rand_st->max_value_dbl);
+}
+
+void hash_password(ulong *result, const char *password)
+{
+  register ulong nr=1345345333L, add=7, nr2=0x12345671L;
+  ulong tmp;
+  for (; *password ; password++)
+  {
+    if (*password == ' ' || *password == '\t')
+      continue;                        /* skipp space in password */
+    tmp= (ulong) (uchar) *password;
+    nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
+    nr2+=(nr2 << 8) ^ nr;
+    add+=tmp;
+  }
+  result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
+  result[1]=nr2 & (((ulong) 1L << 31) -1L);
+  return;
+}
+
+void make_scrambled_password(char *to,const char *password)
+{
+  ulong hash_res[2];
+  hash_password(hash_res,password);
+  sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+}
+
+static inline uint char_val(char X)
+{
+  return (uint) (X >= '0' && X <= '9' ? X-'0' :
+                X >= 'A' && X <= 'Z' ? X-'A'+10 :
+                X-'a'+10);
+}
+
+/*
+** This code assumes that len(password) is divideable with 8 and that
+** res is big enough (2 in mysql)
+*/
+
+void get_salt_from_password(ulong *res,const char *password)
+{
+  res[0]=res[1]=0;
+  if (password)
+  {
+    while (*password)
+    {
+      ulong val=0;
+      uint i;
+      for (i=0 ; i < 8 ; i++)
+       val=(val << 4)+char_val(*password++);
+      *res++=val;
+    }
+  }
+  return;
+}
+
+void make_password_from_salt(char *to, ulong *hash_res)
+{
+  sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+}
+
+
+/*
+ * Genererate a new message based on message and password
+ * The same thing is done in client and server and the results are checked.
+ */
+
+char *scramble(char *to,const char *message,const char *password,
+              my_bool old_ver)
+{
+  struct rand_struct rand_st;
+  ulong hash_pass[2],hash_message[2];
+  if (password && password[0])
+  {
+    char *to_start=to;
+    hash_password(hash_pass,password);
+    hash_password(hash_message,message);
+    if (old_ver)
+      old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
+    else
+      randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+                hash_pass[1] ^ hash_message[1]);
+    while (*message++)
+      *to++= (char) (floor(rnd(&rand_st)*31)+64);
+    if (!old_ver)
+    {                                          /* Make it harder to break */
+      char extra=(char) (floor(rnd(&rand_st)*31));
+      while (to_start != to)
+       *(to_start++)^=extra;
+    }
+  }
+  *to=0;
+  return to;
+}
+
+
+my_bool check_scramble(const char *scrambled, const char *message,
+                      ulong *hash_pass, my_bool old_ver)
+{
+  struct rand_struct rand_st;
+  ulong hash_message[2];
+  char buff[16],*to,extra;                     /* Big enough for check */
+  const char *pos;
+
+  hash_password(hash_message,message);
+  if (old_ver)
+    old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
+  else
+    randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+              hash_pass[1] ^ hash_message[1]);
+  to=buff;
+  for (pos=scrambled ; *pos ; pos++)
+    *to++=(char) (floor(rnd(&rand_st)*31)+64);
+  if (old_ver)
+    extra=0;
+  else
+    extra=(char) (floor(rnd(&rand_st)*31));
+  to=buff;
+  while (*scrambled)
+  {
+    if (*scrambled++ != (char) (*to++ ^ extra))
+      return 1;                                        /* Wrong password */
+  }
+  return 0;
+}
diff --git a/ext/mysql/libmysql/violite.c b/ext/mysql/libmysql/violite.c
new file mode 100644 (file)
index 0000000..396abfd
--- /dev/null
@@ -0,0 +1,386 @@
+/* Copyright Abandoned 2000 Monty Program KB
+   This file is public domain and comes with NO WARRANTY of any kind */
+
+/*
+  Note that we can't have assertion on file descriptors;  The reason for
+  this is that during mysql shutdown, another thread can close a file
+  we are working on.  In this case we should just return read errors from
+  the file descriptior.
+*/
+
+#include <global.h>
+
+#ifndef HAVE_VIO                       /* is Vio suppored by the Vio lib ? */
+
+#include <errno.h>
+#include <assert.h>
+#include <violite.h>
+#include <my_sys.h>
+#include <my_net.h>
+#include <m_string.h>
+
+#if defined(__EMX__)
+#include <sys/ioctl.h>
+#define ioctlsocket(A,B,C) ioctl((A),(B),(void *)(C),sizeof(*(C)))
+#undef HAVE_FCNTL
+#endif                         /* defined(__EMX__) */
+
+#if defined(MSDOS) || defined(__WIN32__)
+#ifdef __WIN32__
+#undef errno
+#undef EINTR
+#undef EAGAIN
+#define errno WSAGetLastError()
+#define EINTR  WSAEINTR
+#define EAGAIN WSAEINPROGRESS
+#endif /* __WIN32__ */
+#define O_NONBLOCK 1    /* For emulation of fcntl() */
+#endif
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif
+
+#ifndef __WIN32__
+#define HANDLE void *
+#endif
+
+struct st_vio
+{
+  my_socket            sd;             /* my_socket - real or imaginary */
+  HANDLE hPipe;
+  my_bool              localhost;      /* Are we from localhost? */
+  int                  fcntl_mode;     /* Buffered fcntl(sd,F_GETFL) */
+  struct sockaddr_in   local;          /* Local internet address */
+  struct sockaddr_in   remote;         /* Remote internet address */
+  enum enum_vio_type   type;           /* Type of connection */
+  char                 desc[30];       /* String description */
+};
+
+typedef void *vio_ptr;
+typedef char *vio_cstring;
+
+/*
+ * Helper to fill most of the Vio* with defaults.
+ */
+
+static void vio_reset(Vio* vio, enum enum_vio_type type,
+                     my_socket sd, HANDLE hPipe,
+                     my_bool localhost)
+{
+  bzero((char*) vio, sizeof(*vio));
+  vio->type    = type;
+  vio->sd      = sd;
+  vio->hPipe   = hPipe;
+  vio->localhost= localhost;
+}
+
+/* Open the socket or TCP/IP connection and read the fnctl() status */
+
+Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost)
+{
+  Vio *vio;
+  DBUG_ENTER("vio_new");
+  DBUG_PRINT("enter", ("sd=%d", sd));
+  if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME))))
+  {
+    vio_reset(vio, type, sd, 0, localhost);
+    sprintf(vio->desc, "socket (%d)", vio->sd);
+#if !defined(___WIN32__) && !defined(__EMX__)
+#if !defined(NO_FCNTL_NONBLOCK)
+    vio->fcntl_mode = fcntl(sd, F_GETFL);
+#endif
+#else /* !defined(__WIN32__) && !defined(__EMX__) */
+    {
+      /* set to blocking mode by default */
+      ulong arg=0;
+      r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
+    }
+#endif
+  }
+  DBUG_RETURN(vio);
+}
+
+
+#ifdef __WIN32__
+
+Vio *vio_new_win32pipe(HANDLE hPipe)
+{
+  Vio *vio;
+  DBUG_ENTER("vio_new_handle");
+  if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
+  {
+    vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE);
+    strmov(vio->desc, "named pipe");
+  }
+  DBUG_RETURN(vio);
+}
+
+#endif
+
+void vio_delete(Vio * vio)
+{
+  /* It must be safe to delete null pointers. */
+  /* This matches the semantics of C++'s delete operator. */
+  if (vio)
+  {
+    if (vio->type != VIO_CLOSED)
+      vio_close(vio);
+    my_free((gptr) vio,MYF(0));
+  }
+}
+
+int vio_errno(Vio *vio __attribute__((unused)))
+{
+  return errno;                        /* On Win32 this mapped to WSAGetLastError() */
+}
+
+
+int vio_read(Vio * vio, gptr buf, int size)
+{
+  int r;
+  DBUG_ENTER("vio_read");
+  DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
+#ifdef __WIN32__
+  if (vio->type == VIO_TYPE_NAMEDPIPE)
+  {
+    DWORD length;
+    if (!ReadFile(vio->hPipe, buf, size, &length, NULL))
+      DBUG_RETURN(-1);
+    DBUG_RETURN(length);
+  }
+  r = recv(vio->sd, buf, size,0);
+#else
+  errno=0;                                     /* For linux */
+  r = read(vio->sd, buf, size);
+#endif /* __WIN32__ */
+#ifndef DBUG_OFF
+  if (r < 0)
+  {
+    DBUG_PRINT("error", ("Got error %d during read",errno));
+  }
+#endif /* DBUG_OFF */
+  DBUG_PRINT("exit", ("%d", r));
+  DBUG_RETURN(r);
+}
+
+
+int vio_write(Vio * vio, const gptr buf, int size)
+{
+  int r;
+  DBUG_ENTER("vio_write");
+  DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
+#ifdef __WIN32__
+  if ( vio->type == VIO_TYPE_NAMEDPIPE)
+  {
+    DWORD length;
+    if (!WriteFile(vio->hPipe, (char*) buf, size, &length, NULL))
+      DBUG_RETURN(-1);
+    DBUG_RETURN(length);
+  }
+  r = send(vio->sd, buf, size,0);
+#else
+  r = write(vio->sd, buf, size);
+#endif /* __WIN32__ */
+#ifndef DBUG_OFF
+  if (r < 0)
+  {
+    DBUG_PRINT("error", ("Got error on write: %d",errno));
+  }
+#endif /* DBUG_OFF */
+  DBUG_PRINT("exit", ("%d", r));
+  DBUG_RETURN(r);
+}
+
+
+int vio_blocking(Vio * vio, my_bool set_blocking_mode)
+{
+  int r=0;
+  DBUG_ENTER("vio_blocking");
+  DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode));
+
+#if !defined(___WIN32__) && !defined(__EMX__)
+#if !defined(NO_FCNTL_NONBLOCK)
+
+  if (vio->sd >= 0)
+  {
+    int old_fcntl=vio->fcntl_mode;
+    if (set_blocking_mode)
+      vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
+    else
+      vio->fcntl_mode |= O_NONBLOCK; /* set bit */
+    if (old_fcntl != vio->fcntl_mode)
+      r = fcntl(vio->sd, F_SETFL, vio->fcntl_mode);
+  }
+#endif /* !defined(NO_FCNTL_NONBLOCK) */
+#else /* !defined(__WIN32__) && !defined(__EMX__) */
+#ifndef __EMX__
+  if (vio->type != VIO_TYPE_NAMEDPIPE)  
+#endif
+  { 
+    ulong arg;
+    int old_fcntl=vio->fcntl_mode;
+    if (set_blocking_mode)
+    {
+      arg = 0;
+      vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
+    }
+    else
+    {
+      arg = 1;
+      vio->fcntl_mode |= O_NONBLOCK; /* set bit */
+    }
+    if (old_fcntl != vio->fcntl_mode)
+      r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
+  }
+#endif /* !defined(__WIN32__) && !defined(__EMX__) */
+  DBUG_RETURN(r);
+}
+
+my_bool
+vio_is_blocking(Vio * vio)
+{
+  my_bool r;
+  DBUG_ENTER("vio_is_blocking");
+  r = !(vio->fcntl_mode & O_NONBLOCK);
+  DBUG_PRINT("exit", ("%d", (int) r));
+  DBUG_RETURN(r);
+}
+
+
+int vio_fastsend(Vio * vio, my_bool onoff)
+{
+  int r=0;
+  DBUG_ENTER("vio_fastsend");
+  DBUG_PRINT("enter", ("onoff:%d", (int) onoff));
+
+#ifdef IPTOS_THROUGHPUT
+  {
+#ifndef __EMX__
+    int tos = IPTOS_THROUGHPUT;
+    if (!setsockopt(vio->sd, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(tos)))
+#endif                         /* !__EMX__ */
+    {
+      int nodelay = 1;
+      if (setsockopt(vio->sd, IPPROTO_TCP, TCP_NODELAY, (void *) &nodelay,
+                    sizeof(nodelay))) {
+       DBUG_PRINT("warning",
+                  ("Couldn't set socket option for fast send"));
+       r= -1;
+      }
+    }
+  }
+#endif /* IPTOS_THROUGHPUT */
+  DBUG_PRINT("exit", ("%d", r));
+  DBUG_RETURN(r);
+}
+
+int vio_keepalive(Vio* vio, my_bool set_keep_alive)
+{
+  int r=0;
+  uint opt = 0;
+  DBUG_ENTER("vio_keepalive");
+  DBUG_PRINT("enter", ("sd=%d, set_keep_alive=%d", vio->sd, (int)
+                      set_keep_alive));
+  if (vio->type != VIO_TYPE_NAMEDPIPE)
+  {
+    if (set_keep_alive)
+      opt = 1;
+    r = setsockopt(vio->sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt,
+                  sizeof(opt));
+  }
+  DBUG_RETURN(r);
+}
+
+
+my_bool
+vio_should_retry(Vio * vio __attribute__((unused)))
+{
+  int en = errno;
+  return en == EAGAIN || en == EINTR || en == EWOULDBLOCK;
+}
+
+
+int vio_close(Vio * vio)
+{
+  int r;
+  DBUG_ENTER("vio_close");
+#ifdef __WIN32__
+  if (vio->type == VIO_TYPE_NAMEDPIPE)
+  {
+#if defined(__NT__) && defined(MYSQL_SERVER)
+    CancelIO(vio->hPipe);
+    DisconnectNamedPipe(vio->hPipe);
+#endif
+    r=CloseHandle(vio->hPipe);
+  }
+  else if (vio->type != VIO_CLOSED)
+#endif /* __WIN32__ */
+  {
+    r=0;
+    if (shutdown(vio->sd,2))
+      r= -1;
+    if (closesocket(vio->sd))
+      r= -1;
+  }
+  if (r)
+  {
+    DBUG_PRINT("error", ("close() failed, error: %d",errno));
+    /* FIXME: error handling (not critical for MySQL) */
+  }
+  vio->type= VIO_CLOSED;
+  vio->sd=   -1;
+  DBUG_RETURN(r);
+}
+
+
+const char *vio_description(Vio * vio)
+{
+  return vio->desc;
+}
+
+enum enum_vio_type vio_type(Vio* vio)
+{
+  return vio->type;
+}
+
+my_socket vio_fd(Vio* vio)
+{
+  return vio->sd;
+}
+
+
+my_bool vio_peer_addr(Vio * vio, char *buf)
+{
+  DBUG_ENTER("vio_peer_addr");
+  DBUG_PRINT("enter", ("sd=%d", vio->sd));
+  if (vio->localhost)
+  {
+    strmov(buf,"127.0.0.1");
+  }
+  else
+  {
+    size_socket addrLen = sizeof(struct sockaddr);
+    if (getpeername(vio->sd, (struct sockaddr *) (& (vio->remote)),
+                   &addrLen) != 0)
+    {
+      DBUG_PRINT("exit", ("getpeername, error: %d", errno));
+      DBUG_RETURN(1);
+    }
+    my_inet_ntoa(vio->remote.sin_addr,buf);
+  }
+  DBUG_PRINT("exit", ("addr=%s", buf));
+  DBUG_RETURN(0);
+}
+
+
+void vio_in_addr(Vio *vio, struct in_addr *in)
+{
+  DBUG_ENTER("vio_in_addr");
+  if (vio->localhost)
+    bzero((char*) in, sizeof(*in));    /* This should never be executed */
+  else
+    *in=vio->remote.sin_addr;
+  DBUG_VOID_RETURN;
+}
+
+#endif /* HAVE_VIO */