summaryrefslogtreecommitdiff
path: root/libmysql
diff options
context:
space:
mode:
Diffstat (limited to 'libmysql')
-rw-r--r--libmysql/.cvsignore10
-rw-r--r--libmysql/Makefile.am149
-rw-r--r--libmysql/acinclude.m491
-rw-r--r--libmysql/conf_to_src.c143
-rw-r--r--libmysql/configure.in230
-rw-r--r--libmysql/dll.c112
-rw-r--r--libmysql/errmsg.c82
-rw-r--r--libmysql/get_password.c212
-rw-r--r--libmysql/libmysql.c2533
-rw-r--r--libmysql/net.c680
-rw-r--r--libmysql/password.c192
-rw-r--r--libmysql/violite.c400
12 files changed, 4834 insertions, 0 deletions
diff --git a/libmysql/.cvsignore b/libmysql/.cvsignore
new file mode 100644
index 00000000000..a58235fee47
--- /dev/null
+++ b/libmysql/.cvsignore
@@ -0,0 +1,10 @@
+*.lo
+.deps
+.libs
+Makefile
+Makefile.in
+conf_to_src
+config.status
+configure
+ctype_extra_sources.c
+libmysqlclient.la
diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am
new file mode 100644
index 00000000000..78c52be3d31
--- /dev/null
+++ b/libmysql/Makefile.am
@@ -0,0 +1,149 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+# MA 02111-1307, USA
+
+# This file is public domain and comes with NO WARRANTY of any kind
+
+MYSQLDATAdir = $(localstatedir)
+MYSQLSHAREdir = $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+INCLUDES = -I$(srcdir)/../include -I../include \
+ -I$(srcdir)/.. -I$(top_srcdir) -I..
+LIBS = @CLIENT_LIBS@
+LDADD = @CLIENT_EXTRA_LDFLAGS@ libmysqlclient.la
+pkglib_LTLIBRARIES = libmysqlclient.la
+
+noinst_PROGRAMS = conf_to_src
+
+# We need .lo, not .o files for everything.
+CHARSET_OBJS=@CHARSET_OBJS@
+LTCHARSET_OBJS= ${CHARSET_OBJS:.o=.lo}
+
+libmysqlclient_la_SOURCES = libmysql.c net.c violite.c password.c \
+ get_password.c errmsg.c
+
+mystringsobjects = strmov.lo strxmov.lo strnmov.lo strmake.lo strend.lo \
+ strnlen.lo strfill.lo is_prefix.lo \
+ int2str.lo str2int.lo strinstr.lo strcont.lo \
+ strcend.lo \
+ bchange.lo bmove.lo bmove_upp.lo longlong2str.lo \
+ strtoull.lo strtoll.lo llstr.lo strto.lo \
+ ctype.lo $(LTCHARSET_OBJS)
+mystringsextra= strto.c ctype_autoconf.c
+dbugobjects = dbug.lo # IT IS IN SAFEMALLOC.C sanity.lo
+mysysheaders = mysys_priv.h my_static.h
+mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
+ my_create.lo my_delete.lo my_tempnam.lo my_open.lo \
+ mf_casecnv.lo my_read.lo my_write.lo errors.lo \
+ my_error.lo my_getwd.lo my_div.lo \
+ mf_pack.lo my_messnc.lo mf_dirname.lo mf_fn_ext.lo\
+ mf_wcomp.lo typelib.lo safemalloc.lo my_alloc.lo \
+ mf_format.lo mf_path.lo mf_unixpath.lo my_fopen.lo \
+ mf_loadpath.lo my_pthread.lo my_thr_init.lo \
+ thr_mutex.lo mulalloc.lo string.lo default.lo \
+ my_compress.lo array.lo my_once.lo list.lo my_net.lo \
+ charset.lo
+# Not needed in the minimum library
+mysysobjects2 = getopt.lo getopt1.lo getvar.lo my_lib.lo
+mysysobjects = $(mysysobjects1) $(mysysobjects2)
+libmysqlclient_la_LIBADD = $(mysysobjects) $(mystringsobjects) $(dbugobjects)
+libmysqlclient_la_LDFLAGS = -version-info @SHARED_LIB_VERSION@
+CLEANFILES = $(libmysqlclient_la_LIBADD) $(SHLIBOBJS) \
+ libmysqclient.la
+DEFS = -DUNDEF_THREADS_HACK \
+ -DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
+ -DDATADIR="\"$(MYSQLDATAdir)\"" \
+ -DSHAREDIR="\"$(MYSQLSHAREdir)\""
+
+# The automatic dependencies miss this
+bmove_upp.lo: $(LTCHARSET_OBJS)
+ctype.c: ctype_extra_sources.c
+
+# This is called from the toplevel makefile
+link_sources:
+ set -x; \
+ ss=`echo $(mystringsobjects) | sed "s;\.lo;.c;g"`; \
+ ds=`echo $(dbugobjects) | sed "s;\.lo;.c;g"`; \
+ ms=`echo $(mysysobjects) | sed "s;\.lo;.c;g"`; \
+ for f in $$ss; do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \
+ done; \
+ for f in $(mystringsextra); do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \
+ done; \
+ for f in $$ds; do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../dbug/$$f $(srcdir)/$$f; \
+ done; \
+ for f in $$ms $(mysysheaders); do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../mysys/$$f $(srcdir)/$$f; \
+ done;
+
+clean-local:
+ rm -f `echo $(mystringsobjects) | sed "s;\.lo;.c;g"` \
+ `echo $(dbugobjects) | sed "s;\.lo;.c;g"` \
+ `echo $(mysysobjects) | sed "s;\.lo;.c;g"` \
+ $(mystringsextra) ctype_extra_sources.c \
+ ../linked_client_sources
+
+ctype_extra_sources.c: conf_to_src
+ ./conf_to_src $(top_srcdir) @CHARSETS_NEED_SOURCE@ > \
+ $(srcdir)/ctype_extra_sources.c
+conf_to_src_SOURCES = conf_to_src.c
+conf_to_src_LDADD=
+
+# This part requires GNUmake
+#
+# This makes a distribution file with only the files needed to compile
+# a minimal MySQL client library
+#
+# For a really minimal distribution (without debugging code) we could
+# keep only the stubs for safemalloc.c and debug.c
+#
+# A list of needed headers collected from the deps information 000213
+nh = global.h config-win32.h dbug.h errmsg.h global.h \
+ m_ctype.h m_string.h \
+ my_alarm.h my_config.h my_dir.h my_list.h my_net.h my_sys.h \
+ mysql.h mysql_com.h mysql_version.h mysqld_error.h mysys_err.h \
+ my_pthread.h thr_alarm.h violite.h
+# Get a list of the needed objects
+lobjs = $(mysysobjects1) $(dbugobjects) $(mystringsobjects)
+
+do-lib-dist:
+ dir=libmysql-$(MYSQL_NO_DASH_VERSION); \
+ srcs1=`echo $(lobjs) | sed "s;\.lo;.c;g"`; \
+ srcs2=$(libmysqlclient_la_SOURCES); \
+ srcs="$$srcs1 $$srcs2"; \
+ objs1=`echo $(lobjs) | sed "s;\.lo;.o;g"`; \
+ objs2=`echo $(libmysqlclient_la_SOURCES) | sed "s;\.c;.o;g"`; \
+ objs="$$objs1 $$objs2"; \
+ rm -rf $$dir; \
+ mkdir $$dir; \
+ cp $$srcs $(mysysheaders) $$dir; \
+ for i in $(nh); do cp ../include/$$i $$dir; done; \
+ echo "# A very minimal Makefile to compile" > $$dir/Makefile; \
+ echo "# the minimized libmysql library" >> $$dir/Makefile; \
+ echo "# This file is autogenerated from Makefile.am" >> $$dir/Makefile; \
+ echo 'CFLAGS= -I. -DUNDEF_THREADS_HACK' >>$$dir/Makefile; \
+ echo "obj=$$objs" >>$$dir/Makefile; \
+ echo 'all: libmysql.a' >>$$dir/Makefile; \
+ echo 'libmysql.a: $$(obj)' >>$$dir/Makefile; \
+ echo ' $$(AR) r $$@ $$?' >>$$dir/Makefile; \
+ gtar cvzf $$dir.tar.gz $$dir; \
+ cd $$dir; gmake
diff --git a/libmysql/acinclude.m4 b/libmysql/acinclude.m4
new file mode 100644
index 00000000000..c0211f3759f
--- /dev/null
+++ b/libmysql/acinclude.m4
@@ -0,0 +1,91 @@
+# Local macros for automake & autoconf
+
+AC_DEFUN(MYSQL_TYPE_ACCEPT,
+[ac_save_CXXFLAGS="$CXXFLAGS"
+AC_CACHE_CHECK([base type of last arg to accept], mysql_cv_btype_last_arg_accept,
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+if test "$ac_cv_prog_gxx" = "yes"
+then
+ CXXFLAGS="$CXXFLAGS -Werror"
+fi
+mysql_cv_btype_last_arg_accept=none
+[AC_TRY_COMPILE([#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+],
+[int a = accept(1, (struct sockaddr *) 0, (socklen_t *) 0);],
+mysql_cv_btype_last_arg_accept=socklen_t)]
+if test $mysql_cv_btype_last_arg_accept = none; then
+[AC_TRY_COMPILE([#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+],
+[int a = accept(1, (struct sockaddr *) 0, (size_t *) 0);],
+mysql_cv_btype_last_arg_accept=size_t)]
+fi
+if test $mysql_cv_btype_last_arg_accept = none; then
+mysql_cv_btype_last_arg_accept=int
+fi)
+AC_LANG_RESTORE
+AC_DEFINE_UNQUOTED(SOCKET_SIZE_TYPE, $mysql_cv_btype_last_arg_accept)
+CXXFLAGS="$ac_save_CXXFLAGS"
+])
+
+
+#---START: Used in for client configure
+AC_DEFUN(MYSQL_CHECK_ULONG,
+[AC_MSG_CHECKING(for type ulong)
+AC_CACHE_VAL(ac_cv_ulong,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ ulong foo;
+ foo++;
+ exit(0);
+}], ac_cv_ulong=yes, ac_cv_ulong=no, ac_cv_ulong=no)])
+AC_MSG_RESULT($ac_cv_ulong)
+if test "$ac_cv_ulong" = "yes"
+then
+ AC_DEFINE(HAVE_ULONG)
+fi
+])
+
+AC_DEFUN(MYSQL_CHECK_UCHAR,
+[AC_MSG_CHECKING(for type uchar)
+AC_CACHE_VAL(ac_cv_uchar,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ uchar foo;
+ foo++;
+ exit(0);
+}], ac_cv_uchar=yes, ac_cv_uchar=no, ac_cv_uchar=no)])
+AC_MSG_RESULT($ac_cv_uchar)
+if test "$ac_cv_uchar" = "yes"
+then
+ AC_DEFINE(HAVE_UCHAR)
+fi
+])
+
+AC_DEFUN(MYSQL_CHECK_UINT,
+[AC_MSG_CHECKING(for type uint)
+AC_CACHE_VAL(ac_cv_uint,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ uint foo;
+ foo++;
+ exit(0);
+}], ac_cv_uint=yes, ac_cv_uint=no, ac_cv_uint=no)])
+AC_MSG_RESULT($ac_cv_uint)
+if test "$ac_cv_uint" = "yes"
+then
+ AC_DEFINE(HAVE_UINT)
+fi
+])
+
+#---END:
diff --git a/libmysql/conf_to_src.c b/libmysql/conf_to_src.c
new file mode 100644
index 00000000000..f75f5af6276
--- /dev/null
+++ b/libmysql/conf_to_src.c
@@ -0,0 +1,143 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* can't use -lmysys because this prog is used to create -lstrings */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define CHARSETS_SUBDIR "sql/share/charsets"
+#define CTYPE_TABLE_SIZE 257
+#define TO_LOWER_TABLE_SIZE 256
+#define TO_UPPER_TABLE_SIZE 256
+#define SORT_ORDER_TABLE_SIZE 256
+#define ROW_LEN 16
+
+void print_arrays_for(char *set);
+
+char *prog;
+char buf[1024], *p, *endptr;
+
+int
+main(int argc, char **argv)
+{
+ prog = *argv;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s source-dir [charset [, charset]]\n", prog);
+ exit(EXIT_FAILURE);
+ }
+
+ --argc; ++argv; /* skip program name */
+
+ if (chdir(*argv) != 0) {
+ fprintf(stderr, "%s: can't cd to %s\n", prog, *argv);
+ exit(EXIT_FAILURE);
+ }
+ --argc; ++argv;
+
+ if (chdir(CHARSETS_SUBDIR) != 0) {
+ fprintf(stderr, "%s: can't cd to %s\n", prog, CHARSETS_SUBDIR);
+ exit(EXIT_FAILURE);
+ }
+
+ while (argc--)
+ print_arrays_for(*argv++);
+
+ exit(EXIT_SUCCESS);
+}
+
+void
+print_array(FILE *f, char *set, char *name, int n)
+{
+ int i;
+ char val[100];
+
+ printf("uchar %s_%s[] = {\n", name, set);
+
+ p = buf;
+ *buf = '\0';
+ for (i = 0; i < n; ++i)
+ {
+ /* get a word from f */
+ endptr = p;
+ for (;;)
+ {
+ while (isspace(*endptr))
+ ++endptr;
+ if (*endptr && *endptr != '#') /* not comment */
+ break;
+ if ((fgets(buf, sizeof(buf), f)) == NULL)
+ return; /* XXX: break silently */
+ endptr = buf;
+ }
+
+ p = val;
+ while (!isspace(*endptr))
+ *p++ = *endptr++;
+ *p = '\0';
+ p = endptr;
+
+ /* write the value out */
+
+ if (i == 0 || i % ROW_LEN == n % ROW_LEN)
+ printf(" ");
+
+ printf("%3d", (unsigned char) strtol(val, (char **) NULL, 16));
+
+ if (i < n - 1)
+ printf(",");
+
+ if ((i+1) % ROW_LEN == n % ROW_LEN)
+ printf("\n");
+ }
+
+ printf("};\n\n");
+}
+
+void
+print_arrays_for(char *set)
+{
+ FILE *f;
+
+ sprintf(buf, "%s.conf", set);
+
+ if ((f = fopen(buf, "r")) == NULL) {
+ fprintf(stderr, "%s: can't read conf file for charset %s\n", prog, set);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("\
+/* The %s character set. Generated automatically by configure and\n\
+ * the %s program\n\
+ */\n\n",
+ set, prog);
+
+ /* it would be nice if this used the code in mysys/charset.c, but... */
+ print_array(f, set, "ctype", CTYPE_TABLE_SIZE);
+ print_array(f, set, "to_lower", TO_LOWER_TABLE_SIZE);
+ print_array(f, set, "to_upper", TO_UPPER_TABLE_SIZE);
+ print_array(f, set, "sort_order", SORT_ORDER_TABLE_SIZE);
+ printf("\n");
+
+ fclose(f);
+
+ return;
+}
diff --git a/libmysql/configure.in b/libmysql/configure.in
new file mode 100644
index 00000000000..22179a33971
--- /dev/null
+++ b/libmysql/configure.in
@@ -0,0 +1,230 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(libmysql.c)
+dnl The version number should be autogenerated from the toplevel configure.in
+AM_INIT_AUTOMAKE(libmysql, 3.23.11-alpha)
+AM_CONFIG_HEADER(my_config.h)
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_LN_S
+AC_PROG_RANLIB
+
+# We use libtool
+AM_PROG_LIBTOOL
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(sgtty.h sys/ioctl.h)
+# Maybe some can be removed but I got sick of adding them on at a time
+# /David
+AC_CHECK_HEADERS(fcntl.h float.h floatingpoint.h ieeefp.h limits.h \
+ memory.h pwd.h select.h \
+ stdlib.h stddef.h \
+ strings.h string.h synch.h sys/mman.h sys/socket.h \
+ sys/timeb.h sys/types.h sys/un.h sys/vadvise.h sys/wait.h term.h \
+ unistd.h utime.h sys/utime.h termio.h termios.h sched.h crypt.h alloca.h)
+
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_CHECK_SIZEOF(char, 1)
+if test "$ac_cv_sizeof_char" -eq 0
+then
+ AC_MSG_ERROR([No size for char type.
+A likely cause for this could be that there isn't any static libraries
+installed. You can verify this by checking if you have libm.a in /lib,
+/usr/lib or some other standard place. If this is the problem,
+install the static libraries and try again. If this isn't the
+problem, examine config.log for possible errors. If you want to
+report this include ALL system information and include at least the
+last 20 rows from config.log!])
+fi
+AC_CHECK_SIZEOF(int, 4)
+if test "$ac_cv_sizeof_int" -eq 0
+then
+ AC_MSG_ERROR("No size for int type.")
+fi
+AC_CHECK_SIZEOF(long, 4)
+if test "$ac_cv_sizeof_long" -eq 0
+then
+ AC_MSG_ERROR("No size for long type.")
+fi
+AC_CHECK_SIZEOF(long long, 8)
+if test "$ac_cv_sizeof_long_long" -eq 0
+then
+ AC_MSG_ERROR("MySQL needs a long long type.")
+fi
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_TYPE_UID_T
+
+# Do the system files define ulong
+MYSQL_CHECK_ULONG
+# Do the system files define uchar
+MYSQL_CHECK_UCHAR
+# Do the system files define uint
+MYSQL_CHECK_UINT
+
+#---START: Used in for client configure
+# Check base type of last arg to accept
+MYSQL_TYPE_ACCEPT
+#---END:
+
+dnl Checks for library functions.
+AC_TYPE_SIGNAL
+# Standard MySQL list
+AC_CHECK_FUNCS(alarm bmove \
+ chsize ftruncate rint finite fpsetmask fpresetsticky\
+ cuserid fcntl fconvert \
+ getrusage getpwuid getcwd getrlimit getwd index locking longjmp \
+ perror pread realpath rename \
+ socket strnlen madvise \
+ strtoul strtoull snprintf tempnam thr_setconcurrency \
+ gethostbyaddr_r gethostbyname_r getpwnam \
+ bfill bzero bcmp strstr strpbrk strerror\
+ tell atod memcpy memmove \
+ setupterm strcasecmp sighold \
+ vidattr setupterm lrand48 localtime_r \
+ sigset sigthreadmask pthread_sigmask pthread_setprio pthread_setprio_np \
+ pthread_setschedparam pthread_attr_setprio pthread_attr_setschedparam \
+ pthread_attr_create pthread_getsequence_np pthread_attr_setstacksize \
+ pthread_condattr_create rwlock_init \
+ crypt dlopen dlerror fchmod getpass getpassphrase)
+
+# This is special for libmysql
+AC_CHECK_FUNCS(strtok_r)
+
+#---START: Used in for client configure
+
+# Check definition of gethostbyname_r (glibc2.0.100 is different from Solaris)
+ac_save_CXXFLAGS="$CXXFLAGS"
+AC_CACHE_CHECK([style of gethostname_r routines], mysql_cv_gethostname_style,
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+if test "$ac_cv_prog_gxx" = "yes"
+then
+ CXXFLAGS="$CXXFLAGS -Werror"
+fi
+AC_TRY_COMPILE(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>],
+[int skr;
+
+ int res = gethostbyname_r((const char *) 0,
+ (struct hostent*) 0, (char*) 0, 0, (struct hostent **) 0, &skr);],
+mysql_cv_gethostname_style=glibc2, mysql_cv_gethostname_style=other))
+AC_LANG_RESTORE
+CXXFLAGS="$ac_save_CXXFLAGS"
+if test "$mysql_cv_gethostname_style" = "glibc2"
+then
+ AC_DEFINE(HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R)
+fi
+
+if test "$with_mit_threads" = "no"
+then
+ # Check definition of pthread_getspecific
+ AC_CACHE_CHECK("args to pthread_getspecific", mysql_cv_getspecific_args,
+ AC_TRY_COMPILE(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h> ],
+[ void *pthread_getspecific(pthread_key_t key);
+pthread_getspecific((pthread_key_t) NULL); ],
+mysql_cv_getspecific_args=POSIX, mysql_cv_getspecific_args=other))
+ if test "$mysql_cv_getspecific_args" = "other"
+ then
+ AC_DEFINE(HAVE_NONPOSIX_PTHREAD_GETSPECIFIC)
+ fi
+
+ # Check definition of pthread_mutex_init
+ AC_CACHE_CHECK("args to pthread_mutex_init", mysql_cv_mutex_init_args,
+ AC_TRY_COMPILE(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h> ],
+[
+ pthread_mutexattr_t attr;
+ pthread_mutex_t mp;
+ pthread_mutex_init(&mp,&attr); ],
+mysql_cv_mutex_init_args=POSIX, mysql_cv_mutex_init_args=other))
+ if test "$mysql_cv_mutex_init_args" = "other"
+ then
+ AC_DEFINE(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT)
+ fi
+fi
+#---END:
+
+#---START: Used in for client configure
+# Check definition of readdir_r
+AC_CACHE_CHECK("args to readdir_r", mysql_cv_readdir_r,
+AC_TRY_LINK(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h>
+#include <dirent.h>],
+[ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
+readdir_r((DIR *) NULL, (struct dirent *) NULL, (struct dirent **) NULL); ],
+mysql_cv_readdir_r=POSIX, mysql_cv_readdir_r=other))
+if test "$mysql_cv_readdir_r" = "POSIX"
+then
+ AC_DEFINE(HAVE_READDIR_R)
+fi
+
+# Check definition av posix sigwait()
+AC_CACHE_CHECK("style of sigwait", mysql_cv_sigwait,
+AC_TRY_LINK(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h>
+#include <signal.h>],
+[#ifndef _AIX
+sigset_t set;
+int sig;
+sigwait(&set,&sig);
+#endif],
+mysql_cv_sigwait=POSIX, mysql_cv_sigwait=other))
+if test "$mysql_cv_sigwait" = "POSIX"
+then
+ AC_DEFINE(HAVE_SIGWAIT)
+fi
+
+if test "$mysql_cv_sigwait" != "POSIX"
+then
+unset mysql_cv_sigwait
+# Check definition av posix sigwait()
+AC_CACHE_CHECK("style of sigwait", mysql_cv_sigwait,
+AC_TRY_LINK(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h>
+#include <signal.h>],
+[sigset_t set;
+int sig;
+sigwait(&set);],
+mysql_cv_sigwait=NONPOSIX, mysql_cv_sigwait=other))
+if test "$mysql_cv_sigwait" = "NONPOSIX"
+then
+ AC_DEFINE(HAVE_NONPOSIX_SIGWAIT)
+fi
+fi
+#---END:
+
+AC_OUTPUT(Makefile)
diff --git a/libmysql/dll.c b/libmysql/dll.c
new file mode 100644
index 00000000000..4c952c5889e
--- /dev/null
+++ b/libmysql/dll.c
@@ -0,0 +1,112 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+** 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 __WIN__
+
+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/libmysql/errmsg.c b/libmysql/errmsg.c
new file mode 100644
index 00000000000..194542afd7f
--- /dev/null
+++ b/libmysql/errmsg.c
@@ -0,0 +1,82 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* 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)",
+ "Can't initialize character set %-.64s (path: %-.64s)",
+ "Got packet bigger than 'max_allowed_packet'"
+};
+
+#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)",
+ "Can't initialize character set %-.64s (path: %-.64s)",
+ "Got packet bigger than 'max_allowed_packet'"
+};
+#endif
+
+
+void init_client_errs(void)
+{
+ errmsg[CLIENT_ERRMAP] = &client_errors[0];
+}
diff --git a/libmysql/get_password.c b/libmysql/get_password.c
new file mode 100644
index 00000000000..d61c40a9559
--- /dev/null
+++ b/libmysql/get_password.c
@@ -0,0 +1,212 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+** 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 __WIN__
+#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 /* __WIN__ */
+#endif /* HAVE_GETPASS */
+
+#ifdef HAVE_GETPASSPHRASE /* For Solaris */
+#define getpass(A) getpassphrase(A)
+#endif
+
+#ifdef __WIN__
+/* 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
+
+
+#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.
+*/
+
+static 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 */
+
+
+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)));
+}
+#endif /*__WIN__*/
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
new file mode 100644
index 00000000000..2b9cd7d2461
--- /dev/null
+++ b/libmysql/libmysql.c
@@ -0,0 +1,2533 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#define DONT_USE_RAID
+#if defined(__WIN__) || defined(_WIN32) || defined(_WIN64)
+#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>
+#include <time.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#if !defined(MSDOS) && !defined(__WIN__)
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#ifdef HAVE_SELECT_H
+# include <select.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+#if defined(THREAD) && !defined(__WIN__)
+#include <my_pthread.h> /* because of signal() */
+#endif
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
+
+static my_bool mysql_client_init=0;
+uint mysql_port=0;
+my_string mysql_unix_port=0;
+
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES | CLIENT_TRANSACTIONS)
+
+#if defined(MSDOS) || defined(__WIN__)
+#define ERRNO WSAGetLastError()
+#define perror(A)
+#else
+#include <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 read_user_name(char *name);
+static void append_wild(char *to,char *end,const char *wild);
+static my_bool mysql_reconnect(MYSQL *mysql);
+static int send_file_to_server(MYSQL *mysql,const char *filename);
+static sig_handler pipe_sig_handler(int sig);
+static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
+ const char *from, ulong length);
+
+/*
+ Let the user specify that we don't want SIGPIPE; This doesn't however work
+ with threaded applications as we can have multiple read in progress.
+*/
+
+#if !defined(__WIN__) && defined(SIGPIPE) && !defined(THREAD)
+#define init_sigpipe_variables sig_return old_signal_handler=(sig_return) 0;
+#define set_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) old_signal_handler=signal(SIGPIPE,pipe_sig_handler)
+#define reset_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) signal(SIGPIPE,old_signal_handler);
+#else
+#define init_sigpipe_variables
+#define set_sigpipe(mysql)
+#define reset_sigpipe(mysql)
+#endif
+
+/****************************************************************************
+* A modified version of connect(). connect2() allows you to specify
+* a timeout value, in seconds, that we should wait until we
+* derermine we can't connect to a particular host. If timeout is 0,
+* connect2() will behave exactly like connect().
+*
+* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
+*****************************************************************************/
+
+static int connect2(File s, const struct sockaddr *name, uint namelen, uint to)
+{
+#if defined(__WIN__)
+ 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;
+ time_t start_time, now_time;
+
+ /* If they passed us a timeout of zero, we should behave
+ * exactly like the normal connect() call does.
+ */
+
+ if (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);
+ /*
+ * select could be interrupted by a signal, and if it is,
+ * the timeout should be adjusted and the select restarted
+ * to work around OSes that don't restart select and
+ * implementations of select that don't adjust tv upon
+ * failure to reflect the time remaining
+ */
+ start_time = time(NULL);
+ for (;;)
+ {
+ tv.tv_sec = (long) to;
+ tv.tv_usec = 0;
+ if ((res = select(s+1, NULL, &sfds, NULL, &tv)) >= 0)
+ break;
+ now_time=time(NULL);
+ to-= (uint) (now_time - start_time);
+ if (errno != EINTR || (int) to <= 0)
+ return -1;
+ }
+
+ /* select() returned something more interesting than zero, let's
+ * see if we have any errors. If the next two statements pass,
+ * we've got an open socket!
+ */
+
+ s_err=0;
+ if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0)
+ return(-1);
+
+ if (s_err)
+ { /* getsockopt() could suceed */
+ errno = s_err;
+ return(-1); /* but return an error... */
+ }
+ return(0); /* It's all good! */
+#endif
+}
+
+/*
+** Create a named pipe connection
+*/
+
+#ifdef __WIN__
+
+HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
+ char **arg_unix_socket)
+{
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+ char szPipeName [ 257 ];
+ DWORD dwMode;
+ int i;
+ my_bool testing_named_pipes=0;
+ char *host= *arg_host, *unix_socket= *arg_unix_socket;
+
+ if ( ! unix_socket || (unix_socket)[0] == 0x00)
+ unix_socket = mysql_unix_port;
+ if (!host || !strcmp(host,LOCAL_HOST))
+ host=LOCAL_HOST_NAMEDPIPE;
+
+ 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=(net->last_errno == ER_NET_PACKET_TOO_LARGE ?
+ CR_NET_PACKET_TOO_LARGE:
+ CR_SERVER_LOST);
+ strmov(net->last_error,ER(net->last_errno));
+ return(packet_error);
+ }
+ if (net->read_pos[0] == 255)
+ {
+ if (len > 3)
+ {
+ char *pos=(char*) net->read_pos+1;
+ if (mysql->protocol_version > 9)
+ { /* New client protocol */
+ net->last_errno=uint2korr(pos);
+ pos+=2;
+ len-=2;
+ }
+ else
+ {
+ net->last_errno=CR_UNKNOWN_ERROR;
+ len--;
+ }
+ (void) strmake(net->last_error,(char*) pos,
+ min(len,sizeof(net->last_error)-1));
+ }
+ else
+ {
+ net->last_errno=CR_UNKNOWN_ERROR;
+ (void) strmov(net->last_error,ER(net->last_errno));
+ }
+ DBUG_PRINT("error",("Got error: %d (%s)", net->last_errno,
+ net->last_error));
+ return(packet_error);
+ }
+ return len;
+}
+
+
+/* Get the length of next field. Change parameter to point at fieldstart */
+static 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;
+ net_clear(net); /* Clear receive buffer */
+ if (!arg)
+ arg="";
+
+ if (net_write_command(net,(uchar) command,arg,
+ length ? length : (ulong) strlen(arg)))
+ {
+ DBUG_PRINT("error",("Can't send command to server. Error: %d",errno));
+ end_server(mysql);
+ if (mysql_reconnect(mysql) ||
+ net_write_command(net,(uchar) command,arg,
+ length ? length : (ulong) strlen(arg)))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ goto end;
+ }
+ }
+ result=0;
+ if (!skipp_check)
+ result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ?
+ -1 : 0);
+ end:
+ reset_sigpipe(mysql);
+ return result;
+}
+
+
+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(__WIN__)
+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 __WIN__
+static my_bool is_NT(void)
+{
+ char *os=getenv("OS");
+ return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
+}
+#endif
+
+/*
+** Expand wildcard to a sql string
+*/
+
+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
+}
+
+
+/**************************************************************************
+** 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",
+ "ssl_key" ,"ssl_cert" ,"ssl_ca" ,"ssl_capath",
+ "character-set-dir", "default-character-set",
+ NullS
+};
+
+static TYPELIB option_types={array_elements(default_options)-1,
+ "options",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;
+#else
+ case 13: /* Ignore SSL options */
+ case 14:
+ case 15:
+ case 16:
+ break;
+#endif /* HAVE_OPENSSL */
+ case 17: /* charset-lib */
+ my_free(options->charset_dir,MYF(MY_ALLOW_ZERO_PTR));
+ options->charset_dir = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case 18:
+ my_free(options->charset_name,MYF(MY_ALLOW_ZERO_PTR));
+ options->charset_name = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ 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 __WIN__
+ mysql->options.connect_timeout=20;
+#endif
+#if defined(SIGPIPE) && defined(THREAD)
+ if (!((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE))
+ (void) signal(SIGPIPE,pipe_sig_handler);
+#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 __WIN__
+ mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
+#else
+ mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
+#endif
+ if ((env = getenv("MYSQL_UNIX_PORT")))
+ mysql_unix_port = env;
+ }
+ mysql_debug(NullS);
+#if defined(SIGPIPE) && !defined(THREAD)
+ (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;
+ mysql->connector_fd->delete();
+ 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],charset_name_buff[16],*end,*host_info, *charset_name;
+ int sock;
+ uint32 ip_addr;
+ struct sockaddr_in sock_addr;
+ uint pkt_length;
+ NET *net= &mysql->net;
+#ifdef __WIN__
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+#endif
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un UNIXaddr;
+#endif
+ init_sigpipe_variables
+ DBUG_ENTER("mysql_real_connect");
+
+ DBUG_PRINT("enter",("host: %s db: %s user: %s",
+ host ? host : "(Null)",
+ db ? db : "(Null)",
+ user ? user : "(Null)"));
+
+ /* Don't give sigpipe errors if the client doesn't want them */
+ set_sigpipe(mysql);
+ net->vio = 0; /* If something goes wrong */
+ /* 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;
+
+ mysql->reconnect=1; /* Reconnect as default */
+ mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
+
+ /*
+ ** 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(__WIN__)
+ {
+ if ((unix_socket ||
+ !host && is_NT() ||
+ host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||
+ mysql->options.named_pipe || !have_tcpip))
+ {
+ sock=0;
+ if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
+ (char**) &host, (char**) &unix_socket)) ==
+ INVALID_HANDLE_VALUE)
+ {
+ DBUG_PRINT("error",
+ ("host: '%s' socket: '%s' named_pipe: %d have_tcpip: %d",
+ host ? host : "<null>",
+ unix_socket ? unix_socket : "<null>",
+ (int) mysql->options.named_pipe,
+ (int) have_tcpip));
+ if (mysql->options.named_pipe ||
+ (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
+ (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
+ goto error; /* User only requested named pipes */
+ /* Try also with TCP/IP */
+ }
+ else
+ {
+ net->vio=vio_new_win32pipe(hPipe);
+ sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host,
+ unix_socket);
+ }
+ }
+ }
+ if (hPipe == INVALID_HANDLE_VALUE)
+#endif
+ {
+ unix_socket=0; /* This is not used */
+ if (!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_fixed(&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);
+ end+=9;
+ if (pkt_length >= (uint) (end+1 - (char*) net->read_pos))
+ mysql->server_capabilities=uint2korr(end);
+ if (pkt_length >= (uint) (end+18 - (char*) net->read_pos))
+ {
+ /* New protocol with 16 bytes to describe server characteristics */
+ mysql->server_language=end[2];
+ mysql->server_status=uint2korr(end+3);
+ }
+
+ /* Set character set */
+ if ((charset_name=mysql->options.charset_name))
+ {
+ const char *save=charsets_dir;
+ if (mysql->options.charset_dir)
+ charsets_dir=mysql->options.charset_dir;
+ mysql->charset=get_charset_by_name(mysql->options.charset_name,
+ MYF(MY_WME));
+ charsets_dir=save;
+ }
+ else if (mysql->server_language)
+ {
+ charset_name=charset_name_buff;
+ sprintf(charset_name,"%d",mysql->server_language); /* In case of errors */
+ mysql->charset=get_charset((uint8) mysql->server_language, MYF(MY_WME));
+ }
+ else
+ mysql->charset=default_charset_info;
+
+ if (!mysql->charset)
+ {
+ net->last_errno=CR_CANT_READ_CHARSET;
+ sprintf(net->last_error,ER(net->last_errno),
+ charset_name ? charset_name : "unknown",
+ mysql->options.charset_dir ? mysql->options.charset_dir :
+ "default");
+ goto error;
+ }
+
+ /* Save connection information */
+ if (!user) user="";
+ if (!passwd) passwd="";
+ if (!my_multi_malloc(MYF(0),
+ &mysql->host_info, (uint) strlen(host_info)+1,
+ &mysql->host, (uint) strlen(host)+1,
+ &mysql->unix_socket,unix_socket ?
+ (uint) strlen(unix_socket)+1 : (uint) 1,
+ &mysql->server_version,
+ (uint) (end - (char*) net->read_pos),
+ NullS) ||
+ !(mysql->user=my_strdup(user,MYF(0))) ||
+ !(mysql->passwd=my_strdup(passwd,MYF(0))))
+ {
+ strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY));
+ goto error;
+ }
+ strmov(mysql->host_info,host_info);
+ strmov(mysql->host,host);
+ if (unix_socket)
+ strmov(mysql->unix_socket,unix_socket);
+ else
+ mysql->unix_socket=0;
+ strmov(mysql->server_version,(char*) net->read_pos+1);
+ mysql->port=port;
+ mysql->client_flag=client_flag | mysql->options.client_flag;
+ DBUG_PRINT("info",("Server version = '%s' capabilites: %ld status: %d",
+ mysql->server_version,mysql->server_capabilities,
+ mysql->server_status));
+
+ /* 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);
+#ifdef _CUSTOMCONFIG_
+#include "_cust_libmysql.h";
+#endif
+ 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->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
+ {
+ /* Allov reconnect next time */
+ mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
+ DBUG_RETURN(1);
+ }
+ mysql_init(&tmp_mysql);
+ tmp_mysql.options=mysql->options;
+ if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
+ mysql->db, mysql->port, mysql->unix_socket,
+ mysql->client_flag))
+ DBUG_RETURN(1);
+ tmp_mysql.free_me=mysql->free_me;
+ mysql->free_me=0;
+ bzero((char*) &mysql->options,sizeof(mysql->options));
+ mysql_close(mysql);
+ *mysql=tmp_mysql;
+ net_clear(&mysql->net);
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ DBUG_RETURN(0);
+}
+
+
+/**************************************************************************
+** Change user and database
+**************************************************************************/
+
+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,(uint) strlen(db),0)))
+ DBUG_RETURN(error);
+ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->db=my_strdup(db,MYF(MY_WME));
+ DBUG_RETURN(0);
+}
+
+
+/*************************************************************************
+** 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.host,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.password,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.unix_socket,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.db,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
+ /* 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, (uint) 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 (mysql->server_capabilities & CLIENT_TRANSACTIONS)
+ {
+ mysql->server_status=uint2korr(pos); pos+=2;
+ }
+ if (pos < mysql->net.read_pos+length && net_field_length(&pos))
+ mysql->info=(char*) pos;
+ DBUG_RETURN(0);
+ }
+ if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
+ {
+ int error=send_file_to_server(mysql,(char*) pos);
+ if ((length=net_safe_read(mysql)) == packet_error || error)
+ DBUG_RETURN(-1);
+ goto get_info; /* Get info packet */
+ }
+ if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
+ mysql->server_status|= SERVER_STATUS_IN_TRANS;
+
+ mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
+ if (!(fields=read_rows(mysql,(MYSQL_FIELD*) 0,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
+ {
+ DBUG_PRINT("info",("end of data"));
+ res->eof=1;
+ res->handle->status=MYSQL_STATUS_READY;
+ }
+ }
+ DBUG_RETURN((MYSQL_ROW) NULL);
+ }
+ {
+ MYSQL_ROW tmp;
+ if (!res->data_cursor)
+ {
+ DBUG_PRINT("info",("end of data"));
+ DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
+ }
+ tmp = res->data_cursor->data;
+ res->data_cursor = res->data_cursor->next;
+ DBUG_RETURN(res->current_row=tmp);
+ }
+}
+
+/**************************************************************************
+** 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(%ld)",(long) row));
+ if (result->data)
+ for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
+ result->current_row=0;
+ result->data_cursor = tmp;
+}
+
+/*************************************************************************
+** put the row or field cursor one a position one got from mysql_row_tell()
+** 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;
+ case MYSQL_SET_CHARSET_DIR:
+ my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.charset_dir=my_strdup(arg,MYF(MY_WME));
+ break;
+ case MYSQL_SET_CHARSET_NAME:
+ my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.charset_name=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 STDCALL mysql_num_rows(MYSQL_RES *res)
+{
+ return res->row_count;
+}
+
+unsigned int STDCALL mysql_num_fields(MYSQL_RES *res)
+{
+ return res->field_count;
+}
+
+my_bool STDCALL mysql_eof(MYSQL_RES *res)
+{
+ return res->eof;
+}
+
+MYSQL_FIELD * STDCALL mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr)
+{
+ return &(res)->fields[fieldnr];
+}
+
+MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res)
+{
+ return (res)->fields;
+}
+
+MYSQL_ROWS * STDCALL mysql_row_tell(MYSQL_RES *res)
+{
+ return res->data_cursor;
+}
+
+uint STDCALL mysql_field_tell(MYSQL_RES *res)
+{
+ return (res)->current_field;
+}
+
+/* MYSQL */
+
+unsigned int STDCALL mysql_field_count(MYSQL *mysql)
+{
+ return mysql->field_count;
+}
+
+my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
+{
+ return (mysql)->affected_rows;
+}
+
+my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
+{
+ return (mysql)->insert_id;
+}
+
+uint STDCALL mysql_errno(MYSQL *mysql)
+{
+ return (mysql)->net.last_errno;
+}
+
+char * STDCALL mysql_error(MYSQL *mysql)
+{
+ return (mysql)->net.last_error;
+}
+
+char *STDCALL mysql_info(MYSQL *mysql)
+{
+ return (mysql)->info;
+}
+
+ulong STDCALL mysql_thread_id(MYSQL *mysql)
+{
+ return (mysql)->thread_id;
+}
+
+const char * STDCALL mysql_character_set_name(MYSQL *mysql)
+{
+ return mysql->charset->name;
+}
+
+
+uint STDCALL mysql_thread_safe(void)
+{
+#ifdef THREAD
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+/****************************************************************************
+** 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)
+{
+ return mysql_sub_escape_string(default_charset_info,to,from,length);
+}
+
+ulong STDCALL
+mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
+ ulong length)
+{
+ return mysql_sub_escape_string(mysql->charset,to,from,length);
+}
+
+
+static ulong
+mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
+ const char *from, ulong length)
+{
+ const char *to_start=to;
+ const char *end;
+#ifdef USE_MB
+ my_bool use_mb_flag=use_mb(charset_info);
+#endif
+ for (end=from+length; from != end ; from++)
+ {
+#ifdef USE_MB
+ int l;
+ if (use_mb_flag && (l = my_ismbchar(charset_info, 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(MYSQL *mysql,
+ 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;
+#ifdef USE_MB
+ my_bool use_mb_flag=use_mb(mysql->charset);
+#endif
+
+ 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 (use_mb_flag && (l = my_ismbchar(mysql->charset, 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;
+}
+
+void STDCALL
+myodbc_remove_escape(MYSQL *mysql,char *name)
+{
+ char *to;
+#ifdef USE_MB
+ my_bool use_mb_flag=use_mb(mysql->charset);
+ char *end;
+ LINT_INIT(end);
+ if (use_mb_flag)
+ for (end=name; *end ; end++) ;
+#endif
+
+ for (to=name ; *name ; name++)
+ {
+#ifdef USE_MB
+ int l;
+ if (use_mb_flag && (l = my_ismbchar( mysql->charset, name , end ) ) )
+ {
+ while (l--)
+ *to++ = *name++;
+ name--;
+ continue;
+ }
+#endif
+ if (*name == '\\' && name[1])
+ name++;
+ *to++= *name;
+ }
+ *to=0;
+}
diff --git a/libmysql/net.c b/libmysql/net.c
new file mode 100644
index 00000000000..643b5e031cf
--- /dev/null
+++ b/libmysql/net.c
@@ -0,0 +1,680 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* 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 __WIN__
+#include <winsock.h>
+#endif
+#include <global.h>
+#include <violite.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+#include "mysqld_error.h"
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <violite.h>
+
+#ifdef MYSQL_SERVER
+ulong max_allowed_packet=65536;
+extern ulong net_read_timeout,net_write_timeout;
+extern uint test_flags;
+#else
+ulong max_allowed_packet=16*1024*1024L;
+ulong net_read_timeout= NET_READ_TIMEOUT;
+ulong net_write_timeout= NET_WRITE_TIMEOUT;
+#endif
+ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
+
+#if !defined(__WIN__) && !defined(MSDOS)
+#include <sys/socket.h>
+#else
+#undef MYSQL_SERVER // Win32 can't handle interrupts
+#endif
+#if !defined(MSDOS) && !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__)
+#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;
+typedef my_bool ALARM;
+#define thr_alarm_init(A) (*A)=0
+#define thr_alarm_in_use(A) (A)
+#define thr_end_alarm(A)
+#define thr_alarm(A,B,C) local_thr_alarm((A),(B),(C))
+static inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __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 statistic_add
+#define statistic_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.
+*/
+
+#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->no_send_ok = 0;
+ net->error=0; net->return_errno=0; net->return_status=0;
+ net->timeout=(uint) 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=0; net->reading_or_writing=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(___WIN__) && !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 (%lu)", length));
+ net->error=1;
+ net->last_errno=ER_NET_PACKET_TOO_LARGE;
+ return 1;
+ }
+ pkt_length = (length+IO_SIZE-1) & ~(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 */
+
+void net_clear(NET *net)
+{
+#ifndef EXTRA_DEBUG
+ int count;
+ bool is_blocking=vio_is_blocking(net->vio);
+ if (is_blocking)
+ 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)));
+ if (is_blocking)
+ vio_blocking(net->vio, TRUE);
+ }
+#endif /* EXTRA_DEBUG */
+ net->pkt_nr=0; /* Ready for new command */
+ net->write_pos=net->buff;
+}
+
+ /* Flush write_buffer if not empty. */
+
+int net_flush(NET *net)
+{
+ int error=0;
+ DBUG_ENTER("net_flush");
+ 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;
+ }
+ DBUG_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;
+#if (!defined(__WIN__) && !defined(__EMX__))
+ ALARM alarm_buff;
+#endif
+ uint retry_count=0;
+ my_bool net_blocking = vio_is_blocking(net->vio);
+ DBUG_ENTER("net_real_write");
+
+ if (net->error == 2)
+ DBUG_RETURN(-1); /* socket can't be used */
+
+ net->reading_or_writing=2;
+#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=2;
+#endif
+ net->reading_or_writing=0;
+ DBUG_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,(uint) net_write_timeout,&alarm_buff);
+#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(__WIN__) && !defined(__EMX__))
+ if ((interrupted || length==0) && !thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(&alarmed,(uint) net_write_timeout,&alarm_buff))
+ { /* 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=2; /* Close socket */
+ goto end;
+ }
+ }
+ retry_count=0;
+ continue;
+ }
+ }
+ else
+#endif /* (!defined(__WIN__) && !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=2; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
+ ER_NET_ERROR_ON_WRITE);
+#endif /* MYSQL_SERVER */
+ break;
+ }
+ pos+=length;
+ statistic_add(bytes_sent,length,&LOCK_bytes_sent);
+ }
+#ifndef __WIN__
+ 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);
+ }
+ net->reading_or_writing=0;
+ DBUG_RETURN(((int) (pos != end)));
+}
+
+
+/*****************************************************************************
+** Read something from server/clinet
+*****************************************************************************/
+
+#ifdef MYSQL_SERVER
+
+/*
+ Help function to clear the commuication buffer when we get a too
+ big packet
+*/
+
+static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
+{
+ char buff[1024];
+ ALARM alarm_buff;
+ uint retry_count=0;
+ if (!thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(alarmed,net->timeout,&alarm_buff) ||
+ (!vio_is_blocking(net->vio) && vio_blocking(net->vio,TRUE) < 0))
+ return; // Can't setup, abort
+ }
+ while (remain > 0)
+ {
+ ulong length;
+ if ((int) (length=vio_read(net->vio,(char*) net->buff,remain)) <= 0L)
+ {
+ my_bool interrupted = vio_should_retry(net->vio);
+ if (!thr_got_alarm(alarmed) && interrupted)
+ { /* Probably in MIT threads */
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+ }
+ return;
+ }
+ remain -=(ulong) length;
+ statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ }
+}
+#endif /* MYSQL_SERVER */
+
+
+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;
+#if (!defined(__WIN__) && !defined(__EMX__)) || defined(MYSQL_SERVER)
+ ALARM alarm_buff;
+#endif
+ my_bool net_blocking=vio_is_blocking(net->vio);
+ ulong remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
+ NET_HEADER_SIZE);
+ *complen = 0;
+
+ net->reading_or_writing=1;
+ thr_alarm_init(&alarmed);
+#ifdef MYSQL_SERVER
+ if (net_blocking)
+ thr_alarm(&alarmed,net->timeout,&alarm_buff);
+#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(__WIN__) && !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,&alarm_buff)) /* 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=2; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_FCNTL_ERROR;
+#endif
+ goto end;
+ }
+ }
+ retry_count=0;
+ continue;
+ }
+ }
+#endif /* (!defined(__WIN__) && !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=2; /* 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;
+ statistic_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)
+ {
+ /* We must allocate one extra byte for the end null */
+ if (net_realloc(net,helping+1))
+ {
+#ifdef MYSQL_SERVER
+ if (i == 1)
+ my_net_skip_rest(net, len, &alarmed);
+#endif
+ 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);
+ }
+ net->reading_or_writing=0;
+ 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=2; /* 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/libmysql/password.c b/libmysql/password.c
new file mode 100644
index 00000000000..0fd5861873a
--- /dev/null
+++ b/libmysql/password.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* 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/libmysql/violite.c b/libmysql/violite.c
new file mode 100644
index 00000000000..349a6fbd849
--- /dev/null
+++ b/libmysql/violite.c
@@ -0,0 +1,400 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ 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(__WIN__)
+#ifdef __WIN__
+#undef errno
+#undef EINTR
+#undef EAGAIN
+#define errno WSAGetLastError()
+#define EINTR WSAEINTR
+#define EAGAIN WSAEINPROGRESS
+#endif /* __WIN__ */
+#define O_NONBLOCK 1 /* For emulation of fcntl() */
+#endif
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif
+
+#ifndef __WIN__
+#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(___WIN__) && !defined(__EMX__)
+#if !defined(NO_FCNTL_NONBLOCK)
+ vio->fcntl_mode = fcntl(sd, F_GETFL);
+#endif
+#else /* !defined(__WIN__) && !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 __WIN__
+
+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 __WIN__
+ 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 /* __WIN__ */
+#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 __WIN__
+ 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 /* __WIN__ */
+#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(___WIN__) && !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(__WIN__) && !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(__WIN__) && !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 __WIN__
+ 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 /* __WIN__ */
+ {
+ 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 */