summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/.cvsignore14
-rw-r--r--client/Attic/libmysql.c2392
-rw-r--r--client/Attic/net.c628
-rw-r--r--client/Makefile.am43
-rw-r--r--client/completion_hash.cc249
-rw-r--r--client/completion_hash.h57
-rw-r--r--client/connect_test.c66
-rw-r--r--client/errmsg.c93
-rw-r--r--client/get_password.c214
-rw-r--r--client/insert_test.c65
-rw-r--r--client/list_test.c86
-rw-r--r--client/my_readline.h34
-rw-r--r--client/mysql.cc2060
-rw-r--r--client/mysqladmin.c1099
-rw-r--r--client/mysqldump.c1285
-rw-r--r--client/mysqlimport.c521
-rw-r--r--client/mysqlshow.c608
-rw-r--r--client/password.c192
-rw-r--r--client/readline.cc216
-rw-r--r--client/select_test.c75
-rw-r--r--client/showdb_test.c80
-rw-r--r--client/sql_string.cc728
-rw-r--r--client/sql_string.h183
-rw-r--r--client/ssl_test.c95
-rw-r--r--client/thread_test.c283
-rw-r--r--client/violite.c394
26 files changed, 11760 insertions, 0 deletions
diff --git a/client/.cvsignore b/client/.cvsignore
new file mode 100644
index 00000000000..54bbaed97f5
--- /dev/null
+++ b/client/.cvsignore
@@ -0,0 +1,14 @@
+.deps
+.libs
+Makefile
+Makefile.in
+insert_test
+mysql
+mysql-test
+mysql_test
+mysqladmin
+mysqldump
+mysqlimport
+mysqlshow
+select_test
+thread_test
diff --git a/client/Attic/libmysql.c b/client/Attic/libmysql.c
new file mode 100644
index 00000000000..4f5e138fd53
--- /dev/null
+++ b/client/Attic/libmysql.c
@@ -0,0 +1,2392 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+#define DONT_USE_RAID
+#if defined(__WIN32__) || defined(WIN32)
+#include <winsock.h>
+#include <odbcinst.h>
+#endif
+#include <global.h>
+#include <my_sys.h>
+#include <mysys_err.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+#include "mysql_version.h"
+#include "mysqld_error.h"
+#include "errmsg.h"
+#include <violite.h>
+#include <sys/stat.h>
+#include <signal.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#if !defined(MSDOS) && !defined(__WIN32__)
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#ifdef HAVE_SELECT_H
+# include <select.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+#if defined(THREAD) && !defined(__WIN32__)
+#include <my_pthread.h> /* because of signal() */
+#endif
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
+
+static my_bool mysql_client_init=0;
+static MYSQL *current_mysql;
+uint mysql_port=0;
+my_string mysql_unix_port=0;
+
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
+
+#if defined(MSDOS) || defined(__WIN32__)
+#define ERRNO WSAGetLastError()
+#define perror(A)
+#else
+#include <sys/errno.h>
+#define ERRNO errno
+#define SOCKET_ERROR -1
+#define closesocket(A) close(A)
+#endif
+
+static void mysql_once_init(void);
+static MYSQL_DATA *read_rows (MYSQL *mysql,MYSQL_FIELD *fields,
+ uint field_count);
+static int read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
+ ulong *lengths);
+static void end_server(MYSQL *mysql);
+static void remember_connection(MYSQL *mysql);
+static void read_user_name(char *name);
+static void append_wild(char *to,char *end,const char *wild);
+static my_bool mysql_reconnect(MYSQL *mysql);
+static int send_file_to_server(MYSQL *mysql,const char *filename);
+static sig_handler pipe_sig_handler(int sig);
+
+/*
+ Let the user specify that we don't want SIGPIPE; This doesn't however work
+ with threaded applications as we can have multiple read in progress.
+*/
+
+#if !defined(__WIN32__) && defined(SIGPIPE) && !defined(THREAD)
+#define init_sigpipe_variables sig_return old_signal_handler;
+#define set_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) old_signal_handler=signal(SIGPIPE,pipe_sig_handler)
+#define reset_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) signal(SIGPIPE,old_signal_handler);
+#else
+#define init_sigpipe_variables
+#define set_sigpipe(mysql)
+#define reset_sigpipe(mysql)
+#endif
+
+/****************************************************************************
+* A modified version of connect(). connect2() allows you to specify
+* a timeout value, in seconds, that we should wait until we
+* derermine we can't connect to a particular host. If timeout is 0,
+* connect2() will behave exactly like connect().
+*
+* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
+*****************************************************************************/
+
+static int connect2(File s, const struct sockaddr *name, uint namelen, uint to)
+{
+#if defined(__WIN32__)
+ return connect(s, (struct sockaddr*) name, namelen);
+#else
+ int flags, res, s_err;
+ size_socket s_err_size = sizeof(uint);
+ fd_set sfds;
+ struct timeval tv;
+
+ /* If they passed us a timeout of zero, we should behave
+ * exactly like the normal connect() call does.
+ */
+
+ if (to == 0)
+ return connect(s, (struct sockaddr*) name, namelen);
+
+ flags = fcntl(s, F_GETFL, 0); /* Set socket to not block */
+#ifdef O_NONBLOCK
+ fcntl(s, F_SETFL, flags | O_NONBLOCK); /* and save the flags.. */
+#endif
+
+ res = connect(s, (struct sockaddr*) name, namelen);
+ s_err = errno; /* Save the error... */
+ fcntl(s, F_SETFL, flags);
+ if ((res != 0) && (s_err != EINPROGRESS))
+ {
+ errno = s_err; /* Restore it */
+ return(-1);
+ }
+ if (res == 0) /* Connected quickly! */
+ return(0);
+
+ /* Otherwise, our connection is "in progress." We can use
+ * the select() call to wait up to a specified period of time
+ * for the connection to suceed. If select() returns 0
+ * (after waiting howevermany seconds), our socket never became
+ * writable (host is probably unreachable.) Otherwise, if
+ * select() returns 1, then one of two conditions exist:
+ *
+ * 1. An error occured. We use getsockopt() to check for this.
+ * 2. The connection was set up sucessfully: getsockopt() will
+ * return 0 as an error.
+ *
+ * Thanks goes to Andrew Gierth <andrew@erlenstar.demon.co.uk>
+ * who posted this method of timing out a connect() in
+ * comp.unix.programmer on August 15th, 1997.
+ */
+
+ FD_ZERO(&sfds);
+ FD_SET(s, &sfds);
+ tv.tv_sec = (long) to;
+ tv.tv_usec = 0;
+ res = select(s+1, NULL, &sfds, NULL, &tv);
+ if (res <= 0) /* Never became writable */
+ return(-1);
+
+ /* select() returned something more interesting than zero, let's
+ * see if we have any errors. If the next two statements pass,
+ * we've got an open socket!
+ */
+
+ s_err=0;
+ if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0)
+ return(-1);
+
+ if (s_err)
+ { /* getsockopt() could suceed */
+ errno = s_err;
+ return(-1); /* but return an error... */
+ }
+ return(0); /* It's all good! */
+#endif
+}
+
+/*
+** Create a named pipe connection
+*/
+
+#ifdef __WIN32__
+
+HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
+ char **arg_unix_socket)
+{
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+ char szPipeName [ 257 ];
+ DWORD dwMode;
+ int i;
+ my_bool testing_named_pipes=0;
+ char *host= *arg_host, *unix_socket= *arg_unix_socket;
+
+ if ( ! unix_socket || (unix_socket)[0] == 0x00)
+ unix_socket = mysql_unix_port;
+ if (!host || !strcmp(host,LOCAL_HOST))
+ host=LOCAL_HOST_NAMEDPIPE;
+
+ sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
+ DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s",
+ host, unix_socket));
+
+ for (i=0 ; i < 100 ; i++) /* Don't retry forever */
+ {
+ if ((hPipe = CreateFile(szPipeName,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL )) != INVALID_HANDLE_VALUE)
+ break;
+ if (GetLastError() != ERROR_PIPE_BUSY)
+ {
+ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ /* wait for for an other instance */
+ if (! WaitNamedPipe(szPipeName, connect_timeout*1000) )
+ {
+ net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ if (hPipe == INVALID_HANDLE_VALUE)
+ {
+ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
+ {
+ CloseHandle( hPipe );
+ net->last_errno=CR_NAMEDPIPESETSTATE_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
+ return (hPipe);
+}
+#endif
+
+
+/*****************************************************************************
+** read a packet from server. Give error message if socket was down
+** or packet is an error message
+*****************************************************************************/
+
+static uint
+net_safe_read(MYSQL *mysql)
+{
+ NET *net= &mysql->net;
+ uint len=0;
+ init_sigpipe_variables
+
+ /* Don't give sigpipe errors if the client doesn't want them */
+ set_sigpipe(mysql);
+ if (net->vio != 0)
+ len=my_net_read(net);
+ reset_sigpipe(mysql);
+
+ if (len == packet_error || len == 0)
+ {
+ DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d",
+ vio_description(net->vio),len));
+ end_server(mysql);
+ net->last_errno=CR_SERVER_LOST;
+ strmov(net->last_error,ER(net->last_errno));
+ return(packet_error);
+ }
+ if (net->read_pos[0] == 255)
+ {
+ if (len > 3)
+ {
+ char *pos=(char*) net->read_pos+1;
+ if (mysql->protocol_version > 9)
+ { /* New client protocol */
+ net->last_errno=uint2korr(pos);
+ pos+=2;
+ len-=2;
+ }
+ else
+ {
+ net->last_errno=CR_UNKNOWN_ERROR;
+ len--;
+ }
+ (void) strmake(net->last_error,(char*) pos,
+ min(len,sizeof(net->last_error)-1));
+ }
+ else
+ {
+ net->last_errno=CR_UNKNOWN_ERROR;
+ (void) strmov(net->last_error,ER(net->last_errno));
+ }
+ DBUG_PRINT("error",("Got error: %d (%s)", net->last_errno,
+ net->last_error));
+ return(packet_error);
+ }
+ return len;
+}
+
+
+/* Get the length of next field. Change parameter to point at fieldstart */
+static ulong
+net_field_length(uchar **packet)
+{
+ reg1 uchar *pos= *packet;
+ if (*pos < 251)
+ {
+ (*packet)++;
+ return (ulong) *pos;
+ }
+ if (*pos == 251)
+ {
+ (*packet)++;
+ return NULL_LENGTH;
+ }
+ if (*pos == 252)
+ {
+ (*packet)+=3;
+ return (ulong) uint2korr(pos+1);
+ }
+ if (*pos == 253)
+ {
+ (*packet)+=4;
+ return (ulong) uint3korr(pos+1);
+ }
+ (*packet)+=9; /* Must be 254 when here */
+ return (ulong) uint4korr(pos+1);
+}
+
+/* Same as above, but returns ulonglong values */
+
+static my_ulonglong
+net_field_length_ll(uchar **packet)
+{
+ reg1 uchar *pos= *packet;
+ if (*pos < 251)
+ {
+ (*packet)++;
+ return (my_ulonglong) *pos;
+ }
+ if (*pos == 251)
+ {
+ (*packet)++;
+ return (my_ulonglong) NULL_LENGTH;
+ }
+ if (*pos == 252)
+ {
+ (*packet)+=3;
+ return (my_ulonglong) uint2korr(pos+1);
+ }
+ if (*pos == 253)
+ {
+ (*packet)+=4;
+ return (my_ulonglong) uint3korr(pos+1);
+ }
+ (*packet)+=9; /* Must be 254 when here */
+#ifdef NO_CLIENT_LONGLONG
+ return (my_ulonglong) uint4korr(pos+1);
+#else
+ return (my_ulonglong) uint8korr(pos+1);
+#endif
+}
+
+
+static void free_rows(MYSQL_DATA *cur)
+{
+ if (cur)
+ {
+ free_root(&cur->alloc);
+ my_free((gptr) cur,MYF(0));
+ }
+}
+
+
+static int
+simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
+ uint length, my_bool skipp_check)
+{
+ NET *net= &mysql->net;
+ int result= -1;
+ init_sigpipe_variables
+
+ /* Don't give sigpipe errors if the client doesn't want them */
+ set_sigpipe(mysql);
+ if (mysql->net.vio == 0)
+ { /* Do reconnect if possible */
+ if (mysql_reconnect(mysql))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ goto end;
+ }
+ }
+ if (mysql->status != MYSQL_STATUS_READY)
+ {
+ strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ goto end;
+ }
+
+ mysql->net.last_error[0]=0;
+ mysql->net.last_errno=0;
+ mysql->info=0;
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ remember_connection(mysql);
+ net_clear(net); /* Clear receive buffer */
+ if (!arg)
+ arg="";
+
+ if (net_write_command(net,(uchar) command,arg,
+ length ? length :strlen(arg)))
+ {
+ DBUG_PRINT("error",("Can't send command to server. Error: %d",errno));
+ end_server(mysql);
+ if (mysql_reconnect(mysql) ||
+ net_write_command(net,(uchar) command,arg,
+ length ? length :strlen(arg)))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ reset_sigpipe(mysql);
+ goto end;
+ }
+ }
+ result=0;
+ if (!skipp_check)
+ result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ?
+ -1 : 0);
+ end:
+ reset_sigpipe(mysql);
+ return result;
+}
+
+
+static void free_old_query(MYSQL *mysql)
+{
+ DBUG_ENTER("free_old_query");
+ if (mysql->fields)
+ free_root(&mysql->field_alloc);
+ init_alloc_root(&mysql->field_alloc,8192); /* Assume rowlength < 8192 */
+ mysql->fields=0;
+ mysql->field_count=0; /* For API */
+ DBUG_VOID_RETURN;
+}
+
+#ifdef HAVE_GETPWUID
+struct passwd *getpwuid(uid_t);
+char* getlogin(void);
+#endif
+
+#if !defined(MSDOS) && ! defined(VMS) && !defined(__WIN32__)
+static void read_user_name(char *name)
+{
+ DBUG_ENTER("read_user_name");
+ if (geteuid() == 0)
+ (void) strmov(name,"root"); /* allow use of surun */
+ else
+ {
+#ifdef HAVE_GETPWUID
+ struct passwd *skr;
+ const char *str;
+/*#ifdef __cplusplus
+ extern "C" struct passwd *getpwuid(uid_t);
+ extern "C" { char* getlogin(void); }
+#else
+ char * getlogin();
+ struct passwd *getpwuid(uid_t);
+#endif
+*/
+ if ((str=getlogin()) == NULL)
+ {
+ if ((skr=getpwuid(geteuid())) != NULL)
+ str=skr->pw_name;
+ else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) &&
+ !(str=getenv("LOGIN")))
+ str="UNKNOWN_USER";
+ }
+ (void) strmake(name,str,USERNAME_LENGTH);
+#elif HAVE_CUSERID
+ (void) cuserid(name);
+#else
+ strmov(name,"UNKNOWN_USER");
+#endif
+ }
+ DBUG_VOID_RETURN;
+}
+
+#else /* If MSDOS || VMS */
+
+static void read_user_name(char *name)
+{
+ char *str=getenv("USER");
+ strmov(name,str ? str : "ODBC"); /* ODBC will send user variable */
+}
+
+#endif
+
+#ifdef __WIN32__
+static my_bool is_NT(void)
+{
+ char *os=getenv("OS");
+ return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
+}
+#endif
+
+/*
+** Expand wildcard to a sql string
+*/
+
+static void
+append_wild(char *to, char *end, const char *wild)
+{
+ end-=5; /* Some extra */
+ if (wild && wild[0])
+ {
+ to=strmov(to," like '");
+ while (*wild && to < end)
+ {
+ if (*wild == '\\' || *wild == '\'')
+ *to++='\\';
+ *to++= *wild++;
+ }
+ if (*wild) /* Too small buffer */
+ *to++='%'; /* Nicer this way */
+ to[0]='\'';
+ to[1]=0;
+ }
+}
+
+
+
+/**************************************************************************
+** Init debugging if MYSQL_DEBUG environment variable is found
+**************************************************************************/
+
+void STDCALL
+mysql_debug(const char *debug)
+{
+#ifndef DBUG_OFF
+ char *env;
+ if (_db_on_)
+ return; /* Already using debugging */
+ if (debug)
+ {
+ DEBUGGER_ON;
+ DBUG_PUSH(debug);
+ }
+ else if ((env = getenv("MYSQL_DEBUG")))
+ {
+ DEBUGGER_ON;
+ DBUG_PUSH(env);
+#if !defined(_WINVER) && !defined(WINVER)
+ puts("\n-------------------------------------------------------");
+ puts("MYSQL_DEBUG found. libmysql started with the following:");
+ puts(env);
+ puts("-------------------------------------------------------\n");
+#else
+ {
+ char buff[80];
+ strmov(strmov(buff,"libmysql: "),env);
+ MessageBox((HWND) 0,"Debugging variable MYSQL_DEBUG used",buff,MB_OK);
+ }
+#endif
+ }
+#endif
+}
+
+
+/**************************************************************************
+** Store the server socket currently in use
+** Used by pipe_handler if error on socket interrupt
+**************************************************************************/
+
+static void
+remember_connection(MYSQL *mysql)
+{
+ current_mysql = mysql;
+}
+
+/**************************************************************************
+** Close the server connection if we get a SIGPIPE
+ ARGSUSED
+**************************************************************************/
+
+static sig_handler
+pipe_sig_handler(int sig __attribute__((unused)))
+{
+ DBUG_PRINT("info",("Hit by signal %d",sig));
+#ifdef DONT_REMEMBER_SIGNAL
+ (void) signal(SIGPIPE,pipe_sig_handler);
+#endif
+}
+
+
+/**************************************************************************
+** Shut down connection
+**************************************************************************/
+
+static void
+end_server(MYSQL *mysql)
+{
+ DBUG_ENTER("end_server");
+ if (mysql->net.vio != 0)
+ {
+ init_sigpipe_variables
+ DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio)));
+ set_sigpipe(mysql);
+ vio_delete(mysql->net.vio);
+ reset_sigpipe(mysql);
+ mysql->net.vio= 0; /* Marker */
+ }
+ net_end(&mysql->net);
+ free_old_query(mysql);
+ DBUG_VOID_RETURN;
+}
+
+
+void STDCALL
+mysql_free_result(MYSQL_RES *result)
+{
+ DBUG_ENTER("mysql_free_result");
+ DBUG_PRINT("enter",("mysql_res: %lx",result));
+ if (result)
+ {
+ if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
+ {
+ DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows"));
+ for (;;)
+ {
+ uint pkt_len;
+ if ((pkt_len=(uint) net_safe_read(result->handle)) == packet_error)
+ break;
+ if (pkt_len == 1 && result->handle->net.read_pos[0] == 254)
+ break; /* End of data */
+ }
+ result->handle->status=MYSQL_STATUS_READY;
+ }
+ free_rows(result->data);
+ if (result->fields)
+ free_root(&result->field_alloc);
+ if (result->row)
+ my_free((gptr) result->row,MYF(0));
+ my_free((gptr) result,MYF(0));
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/****************************************************************************
+** Get options from my.cnf
+****************************************************************************/
+
+static const char *default_options[]=
+{"port","socket","compress","password","pipe", "timeout", "user",
+ "init-command", "host", "database", "debug", "return-found-rows",
+#ifdef HAVE_OPENSSL
+ "ssl_key" ,"ssl_cert" ,"ssl_ca" ,"ssl_capath",
+#endif /* HAVE_OPENSSL */
+ NullS
+};
+static TYPELIB option_types={array_elements(default_options)-1,(char*) "options",(char **) default_options};
+
+static void mysql_read_default_options(struct st_mysql_options *options,
+ const char *filename,const char *group)
+{
+ int argc;
+ char *argv_buff[1],**argv;
+ const char *groups[3];
+ DBUG_ENTER("mysql_read_default_options");
+ DBUG_PRINT("enter",("file: %s group: %s",filename,group ? group :"NULL"));
+
+ argc=1; argv=argv_buff; argv_buff[0]= (char*) "client";
+ groups[0]= (char*) "client"; groups[1]= (char*) group; groups[2]=0;
+
+ load_defaults(filename, groups, &argc, &argv);
+ if (argc != 1) /* If some default option */
+ {
+ char **option=argv;
+ while (*++option)
+ {
+ /* DBUG_PRINT("info",("option: %s",option[0])); */
+ if (option[0][0] == '-' && option[0][1] == '-')
+ {
+ char *end=strcend(*option,'=');
+ char *opt_arg=0;
+ if (*end)
+ {
+ opt_arg=end+1;
+ *end=0; /* Remove '=' */
+ }
+ switch (find_type(*option+2,&option_types,2)) {
+ case 1: /* port */
+ if (opt_arg)
+ options->port=atoi(opt_arg);
+ break;
+ case 2: /* socket */
+ if (opt_arg)
+ {
+ my_free(options->unix_socket,MYF(MY_ALLOW_ZERO_PTR));
+ options->unix_socket=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 3: /* compress */
+ options->compress=1;
+ break;
+ case 4: /* password */
+ if (opt_arg)
+ {
+ my_free(options->password,MYF(MY_ALLOW_ZERO_PTR));
+ options->password=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 5: /* pipe */
+ options->named_pipe=1; /* Force named pipe */
+ break;
+ case 6: /* timeout */
+ if (opt_arg)
+ options->connect_timeout=atoi(opt_arg);
+ break;
+ case 7: /* user */
+ if (opt_arg)
+ {
+ my_free(options->user,MYF(MY_ALLOW_ZERO_PTR));
+ options->user=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 8: /* init-command */
+ if (opt_arg)
+ {
+ my_free(options->init_command,MYF(MY_ALLOW_ZERO_PTR));
+ options->init_command=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 9: /* host */
+ if (opt_arg)
+ {
+ my_free(options->host,MYF(MY_ALLOW_ZERO_PTR));
+ options->host=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 10: /* database */
+ if (opt_arg)
+ {
+ my_free(options->db,MYF(MY_ALLOW_ZERO_PTR));
+ options->db=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 11: /* debug */
+ mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace");
+ break;
+ case 12: /* return-found-rows */
+ options->client_flag|=CLIENT_FOUND_ROWS;
+ break;
+#ifdef HAVE_OPENSSL
+ case 13: /* ssl_key */
+ my_free(options->ssl_key, MYF(MY_ALLOW_ZERO_PTR));
+ options->ssl_key = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case 14: /* ssl_cert */
+ my_free(options->ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
+ options->ssl_cert = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case 15: /* ssl_ca */
+ my_free(options->ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
+ options->ssl_ca = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case 16: /* ssl_capath */
+ my_free(options->ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
+ options->ssl_capath = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+#endif /* HAVE_OPENSSL */
+ default:
+ DBUG_PRINT("warning",("unknown option: %s",option[0]));
+ }
+ }
+ }
+ }
+ free_defaults(argv);
+ DBUG_VOID_RETURN;
+}
+
+
+/***************************************************************************
+** Change field rows to field structs
+***************************************************************************/
+
+static MYSQL_FIELD *
+unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
+ my_bool default_value, my_bool long_flag_protocol)
+{
+ MYSQL_ROWS *row;
+ MYSQL_FIELD *field,*result;
+ DBUG_ENTER("unpack_fields");
+
+ field=result=(MYSQL_FIELD*) alloc_root(alloc,sizeof(MYSQL_FIELD)*fields);
+ if (!result)
+ DBUG_RETURN(0);
+
+ for (row=data->data; row ; row = row->next,field++)
+ {
+ field->table= strdup_root(alloc,(char*) row->data[0]);
+ field->name= strdup_root(alloc,(char*) row->data[1]);
+ field->length= (uint) uint3korr(row->data[2]);
+ field->type= (enum enum_field_types) (uchar) row->data[3][0];
+ if (long_flag_protocol)
+ {
+ field->flags= uint2korr(row->data[4]);
+ field->decimals=(uint) (uchar) row->data[4][2];
+ }
+ else
+ {
+ field->flags= (uint) (uchar) row->data[4][0];
+ field->decimals=(uint) (uchar) row->data[4][1];
+ }
+ if (default_value && row->data[5])
+ field->def=strdup_root(alloc,(char*) row->data[5]);
+ else
+ field->def=0;
+ field->max_length= 0;
+ }
+ free_rows(data); /* Free old data */
+ DBUG_RETURN(result);
+}
+
+
+/* Read all rows (fields or data) from server */
+
+static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
+ uint fields)
+{
+ uint field,pkt_len;
+ ulong len;
+ uchar *cp;
+ char *to;
+ MYSQL_DATA *result;
+ MYSQL_ROWS **prev_ptr,*cur;
+ NET *net = &mysql->net;
+ DBUG_ENTER("read_rows");
+
+ if ((pkt_len=(uint) net_safe_read(mysql)) == packet_error)
+ DBUG_RETURN(0);
+ if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ net->last_errno=CR_OUT_OF_MEMORY;
+ strmov(net->last_error,ER(net->last_errno));
+ DBUG_RETURN(0);
+ }
+ init_alloc_root(&result->alloc,8192); /* Assume rowlength < 8192 */
+ result->alloc.min_malloc=sizeof(MYSQL_ROWS);
+ prev_ptr= &result->data;
+ result->rows=0;
+ result->fields=fields;
+
+ while (*(cp=net->read_pos) != 254 || pkt_len != 1)
+ {
+ result->rows++;
+ if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
+ sizeof(MYSQL_ROWS))) ||
+ !(cur->data= ((MYSQL_ROW)
+ alloc_root(&result->alloc,
+ (fields+1)*sizeof(char *)+pkt_len))))
+ {
+ free_rows(result);
+ net->last_errno=CR_OUT_OF_MEMORY;
+ strmov(net->last_error,ER(net->last_errno));
+ DBUG_RETURN(0);
+ }
+ *prev_ptr=cur;
+ prev_ptr= &cur->next;
+ to= (char*) (cur->data+fields+1);
+ for (field=0 ; field < fields ; field++)
+ {
+ if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH)
+ { /* null field */
+ cur->data[field] = 0;
+ }
+ else
+ {
+ cur->data[field] = to;
+ memcpy(to,(char*) cp,len); to[len]=0;
+ to+=len+1;
+ cp+=len;
+ if (mysql_fields)
+ {
+ if (mysql_fields[field].max_length < len)
+ mysql_fields[field].max_length=len;
+ }
+ }
+ }
+ cur->data[field]=to; /* End of last field */
+ if ((pkt_len=net_safe_read(mysql)) == packet_error)
+ {
+ free_rows(result);
+ DBUG_RETURN(0);
+ }
+ }
+ *prev_ptr=0; /* last pointer is null */
+ DBUG_PRINT("exit",("Got %d rows",result->rows));
+ DBUG_RETURN(result);
+}
+
+
+/*
+** Read one row. Uses packet buffer as storage for fields.
+** When next packet is read, the previous field values are destroyed
+*/
+
+
+static int
+read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
+{
+ uint field;
+ ulong pkt_len,len;
+ uchar *pos,*prev_pos;
+
+ if ((pkt_len=(uint) net_safe_read(mysql)) == packet_error)
+ return -1;
+ if (pkt_len == 1 && mysql->net.read_pos[0] == 254)
+ return 1; /* End of data */
+ prev_pos= 0; /* allowed to write at packet[-1] */
+ pos=mysql->net.read_pos;
+ for (field=0 ; field < fields ; field++)
+ {
+ if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH)
+ { /* null field */
+ row[field] = 0;
+ *lengths++=0;
+ }
+ else
+ {
+ row[field] = (char*) pos;
+ pos+=len;
+ *lengths++=len;
+ }
+ if (prev_pos)
+ *prev_pos=0; /* Terminate prev field */
+ prev_pos=pos;
+ }
+ row[field]=(char*) prev_pos+1; /* End of last field */
+ *prev_pos=0; /* Terminate last field */
+ return 0;
+}
+
+/****************************************************************************
+** Init MySQL structure or allocate one
+****************************************************************************/
+
+MYSQL * STDCALL
+mysql_init(MYSQL *mysql)
+{
+ mysql_once_init();
+ if (!mysql)
+ {
+ if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
+ return 0;
+ mysql->free_me=1;
+ mysql->net.vio = 0;
+ }
+ else
+ bzero((char*) (mysql),sizeof(*(mysql)));
+#ifdef __WIN32__
+ mysql->options.connect_timeout=20;
+#endif
+ return mysql;
+}
+
+
+static void mysql_once_init()
+{
+ if (!mysql_client_init)
+ {
+ mysql_client_init=1;
+ my_init(); /* Will init threads */
+ init_client_errs();
+ if (!mysql_port)
+ {
+ mysql_port = MYSQL_PORT;
+#ifndef MSDOS
+ {
+ struct servent *serv_ptr;
+ char *env;
+ if ((serv_ptr = getservbyname("mysql", "tcp")))
+ mysql_port = (uint) ntohs((ushort) serv_ptr->s_port);
+ if ((env = getenv("MYSQL_TCP_PORT")))
+ mysql_port =(uint) atoi(env);
+ }
+#endif
+ }
+ if (!mysql_unix_port)
+ {
+ char *env;
+#ifdef __WIN32__
+ mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
+#else
+ mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
+#endif
+ if ((env = getenv("MYSQL_UNIX_PORT")))
+ mysql_unix_port = env;
+ }
+ mysql_debug(NullS);
+#if defined(SIGPIPE) && !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;
+ delete reinterpret_cast<VioConnectorFd*>(mysql->connector_fd);
+ mysql->connector_fd = 0;
+ return 0;
+}
+#endif /* HAVE_OPENSSL */
+
+/**************************************************************************
+** Connect to sql server
+** If host == 0 then use localhost
+**************************************************************************/
+
+MYSQL * STDCALL
+mysql_connect(MYSQL *mysql,const char *host,
+ const char *user, const char *passwd)
+{
+ MYSQL *res;
+ mysql=mysql_init(mysql); /* Make it thread safe */
+ {
+ DBUG_ENTER("mysql_connect");
+ if (!(res=mysql_real_connect(mysql,host,user,passwd,NullS,0,NullS,0)))
+ {
+ if (mysql->free_me)
+ my_free((gptr) mysql,MYF(0));
+ }
+ DBUG_RETURN(res);
+ }
+}
+
+
+/*
+** Note that the mysql argument must be initialized with mysql_init()
+** before calling mysql_real_connect !
+*/
+
+MYSQL * STDCALL
+mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
+ const char *passwd, const char *db,
+ uint port, const char *unix_socket,uint client_flag)
+{
+ char buff[100],*end,*host_info;
+ int sock;
+ ulong ip_addr;
+ struct sockaddr_in sock_addr;
+ uint pkt_length;
+ NET *net;
+#ifdef __WIN32__
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+#endif
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un UNIXaddr;
+#endif
+ init_sigpipe_variables
+ DBUG_ENTER("mysql_real_connect");
+
+ DBUG_PRINT("enter",("host: %s db: %s user: %s",
+ host ? host : "(Null)",
+ db ? db : "(Null)",
+ user ? user : "(Null)"));
+
+ /* Don't give sigpipe errors if the client doesn't want them */
+ set_sigpipe(mysql);
+ /* use default options */
+ if (mysql->options.my_cnf_file || mysql->options.my_cnf_group)
+ {
+ mysql_read_default_options(&mysql->options,
+ (mysql->options.my_cnf_file ?
+ mysql->options.my_cnf_file : "my"),
+ mysql->options.my_cnf_group);
+ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.my_cnf_file=mysql->options.my_cnf_group=0;
+ }
+
+ /* Some empty-string-tests are done because of ODBC */
+ if (!host || !host[0])
+ host=mysql->options.host;
+ if (!user || !user[0])
+ user=mysql->options.user;
+ if (!passwd)
+ {
+ passwd=mysql->options.password;
+#ifndef DONT_USE_MYSQL_PWD
+ if (!passwd)
+ passwd=getenv("MYSQL_PWD"); /* get it from environment (haneke) */
+#endif
+ }
+ if (!db || !db[0])
+ db=mysql->options.db;
+ if (!port)
+ port=mysql->options.port;
+ if (!unix_socket)
+ unix_socket=mysql->options.unix_socket;
+
+ remember_connection(mysql);
+ mysql->reconnect=1; /* Reconnect as default */
+ net= &mysql->net;
+ net->vio = 0; /* If something goes wrong */
+
+ /*
+ ** Grab a socket and connect it to the server
+ */
+
+#if defined(HAVE_SYS_UN_H)
+ if ((!host || !strcmp(host,LOCAL_HOST)) && (unix_socket || mysql_unix_port))
+ {
+ host=LOCAL_HOST;
+ if (!unix_socket)
+ unix_socket=mysql_unix_port;
+ host_info=(char*) ER(CR_LOCALHOST_CONNECTION);
+ DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
+ if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
+ {
+ net->last_errno=CR_SOCKET_CREATE_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),ERRNO);
+ goto error;
+ }
+ net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
+ bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
+ UNIXaddr.sun_family = AF_UNIX;
+ strmov(UNIXaddr.sun_path, unix_socket);
+ if (connect2(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
+ mysql->options.connect_timeout) <0)
+ {
+ DBUG_PRINT("error",("Got error %d on connect to local server",ERRNO));
+ net->last_errno=CR_CONNECTION_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),unix_socket,ERRNO);
+ goto error;
+ }
+ }
+ else
+#elif defined(__WIN32__)
+ {
+ if ((unix_socket ||
+ !host && is_NT() ||
+ host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||
+ mysql->options.named_pipe || !have_tcpip))
+ {
+ sock=0;
+ if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
+ (char**) &host, (char**) &unix_socket)) ==
+ INVALID_HANDLE_VALUE)
+ {
+ DBUG_PRINT("error",
+ ("host: '%s' socket: '%s' named_pipe: %d have_tcpip: %d",
+ host ? host : "<null>",
+ unix_socket ? unix_socket : "<null>",
+ (int) mysql->options.named_pipe,
+ (int) have_tcpip));
+ if (mysql->options.named_pipe ||
+ (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
+ (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
+ goto error; /* User only requested named pipes */
+ /* Try also with TCP/IP */
+ }
+ else
+ {
+ net->vio=vio_new_win32pipe(hPipe);
+ sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host,
+ unix_socket);
+ }
+ }
+ }
+ if (hPipe == INVALID_HANDLE_VALUE)
+#endif
+ {
+ unix_socket=0; /* This is not used */
+ if (!port)
+ port=mysql_port;
+ if (!host)
+ host=LOCAL_HOST;
+ sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
+ DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
+ if ((sock = socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
+ {
+ net->last_errno=CR_IPSOCK_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),ERRNO);
+ goto error;
+ }
+ net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
+ bzero((char*) &sock_addr,sizeof(sock_addr));
+ sock_addr.sin_family = AF_INET;
+
+ /*
+ ** The server name may be a host name or IP address
+ */
+
+ if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE)
+ {
+ memcpy(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr));
+ }
+ else
+#if defined(HAVE_GETHOSTBYNAME_R) && defined(_REENTRANT) && defined(THREAD)
+ {
+ int tmp_errno;
+ struct hostent tmp_hostent,*hp;
+ char buff2[GETHOSTBYNAME_BUFF_SIZE];
+ hp = my_gethostbyname_r(host,&tmp_hostent,buff2,sizeof(buff2),
+ &tmp_errno);
+ if (!hp)
+ {
+ net->last_errno=CR_UNKNOWN_HOST;
+ sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, tmp_errno);
+ goto error;
+ }
+ memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+ }
+#else
+ {
+ struct hostent *hp;
+ if (!(hp=gethostbyname(host)))
+ {
+ net->last_errno=CR_UNKNOWN_HOST;
+ sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, errno);
+ goto error;
+ }
+ memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+ }
+#endif
+ sock_addr.sin_port = (ushort) htons((ushort) port);
+ if (connect2(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
+ mysql->options.connect_timeout) <0)
+ {
+ DBUG_PRINT("error",("Got error %d on connect to '%s'",ERRNO,host));
+ net->last_errno= CR_CONN_HOST_ERROR;
+ sprintf(net->last_error ,ER(CR_CONN_HOST_ERROR), host, ERRNO);
+ goto error;
+ }
+ }
+
+ if (!net->vio || my_net_init(net, net->vio))
+ {
+ vio_delete(net->vio);
+ net->last_errno=CR_OUT_OF_MEMORY;
+ strmov(net->last_error,ER(net->last_errno));
+ goto error;
+ }
+ vio_keepalive(net->vio,TRUE);
+
+ /* Get version info */
+ mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
+ if ((pkt_length=net_safe_read(mysql)) == packet_error)
+ goto error;
+
+ /* Check if version of protocoll matches current one */
+
+ mysql->protocol_version= net->read_pos[0];
+ DBUG_DUMP("packet",(char*) net->read_pos,10);
+ DBUG_PRINT("info",("mysql protocol version %d, server=%d",
+ PROTOCOL_VERSION, mysql->protocol_version));
+ if (mysql->protocol_version != PROTOCOL_VERSION &&
+ mysql->protocol_version != PROTOCOL_VERSION-1)
+ {
+ net->last_errno= CR_VERSION_ERROR;
+ sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version,
+ PROTOCOL_VERSION);
+ goto error;
+ }
+ end=strend((char*) net->read_pos+1);
+ mysql->thread_id=uint4korr(end+1);
+ end+=5;
+ strmake(mysql->scramble_buff,end,8);
+ if (pkt_length > (uint) (end+9 - (char*) net->read_pos))
+ mysql->server_capabilities=uint2korr(end+9);
+
+ /* Save connection information */
+ if (!user) user="";
+ if (!passwd) passwd="";
+ if (!my_multi_malloc(MYF(0),
+ &mysql->host_info,strlen(host_info)+1,
+ &mysql->host,strlen(host)+1,
+ &mysql->unix_socket,unix_socket ? strlen(unix_socket)+1
+ :1,
+ &mysql->server_version,
+ (uint) (end - (char*) net->read_pos),
+ NullS) ||
+ !(mysql->user=my_strdup(user,MYF(0))) ||
+ !(mysql->passwd=my_strdup(passwd,MYF(0))))
+ {
+ strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY));
+ goto error;
+ }
+ strmov(mysql->host_info,host_info);
+ strmov(mysql->host,host);
+ if (unix_socket)
+ strmov(mysql->unix_socket,unix_socket);
+ else
+ mysql->unix_socket=0;
+ strmov(mysql->server_version,(char*) net->read_pos+1);
+ mysql->port=port;
+ mysql->client_flag=client_flag | mysql->options.client_flag;
+ DBUG_PRINT("info",("Server version = '%s' capabilites: %ld",
+ mysql->server_version,mysql->server_capabilities));
+
+ /* Send client information for access check */
+ client_flag|=CLIENT_CAPABILITIES;
+
+#ifdef HAVE_OPENSSL
+ if (mysql->options.use_ssl)
+ client_flag|=CLIENT_SSL;
+#endif /* HAVE_OPENSSL */
+
+ if (db)
+ client_flag|=CLIENT_CONNECT_WITH_DB;
+#ifdef HAVE_COMPRESS
+ if (mysql->server_capabilities & CLIENT_COMPRESS &&
+ (mysql->options.compress || client_flag & CLIENT_COMPRESS))
+ client_flag|=CLIENT_COMPRESS; /* We will use compression */
+ else
+#endif
+ client_flag&= ~CLIENT_COMPRESS;
+
+#ifdef HAVE_OPENSSL
+ if ((mysql->server_capabilities & CLIENT_SSL) &&
+ (mysql->options.use_ssl || (client_flag & CLIENT_SSL)))
+ {
+ DBUG_PRINT("info", ("Changing IO layer to SSL"));
+ client_flag |= CLIENT_SSL;
+ }
+ else
+ {
+ if (client_flag & CLIENT_SSL)
+ {
+ DBUG_PRINT("info", ("Leaving IO layer intact because server doesn't support SSL"));
+ }
+ client_flag &= ~CLIENT_SSL;
+ }
+#endif /* HAVE_OPENSSL */
+
+ int2store(buff,client_flag);
+ mysql->client_flag=client_flag;
+
+#ifdef HAVE_OPENSSL
+ /* Oops.. are we careful enough to not send ANY information */
+ /* without encryption? */
+ if (client_flag & CLIENT_SSL)
+ {
+ if (my_net_write(net,buff,(uint) (2)) || net_flush(net))
+ goto error;
+ /* Do the SSL layering. */
+ DBUG_PRINT("info", ("IO layer change in progress..."));
+ VioSSLConnectorFd* connector_fd = (VioSSLConnectorFd*)
+ (mysql->connector_fd);
+ VioSocket* vio_socket = (VioSocket*)(mysql->net.vio);
+ VioSSL* vio_ssl = connector_fd->connect(vio_socket);
+ mysql->net.vio = (NetVio*)(vio_ssl);
+ }
+#endif /* HAVE_OPENSSL */
+
+ int3store(buff+2,max_allowed_packet);
+ if (user && user[0])
+ strmake(buff+5,user,32);
+ else
+ read_user_name((char*) buff+5);
+#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->host_info)
+ DBUG_RETURN(1);
+ mysql_init(&tmp_mysql);
+ tmp_mysql.options=mysql->options;
+ if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
+ mysql->db, mysql->port, mysql->unix_socket,
+ mysql->client_flag))
+ DBUG_RETURN(1);
+ tmp_mysql.free_me=mysql->free_me;
+ mysql->free_me=0;
+ bzero((char*) &mysql->options,sizeof(&mysql->options));
+ mysql_close(mysql);
+ memcpy(mysql,&tmp_mysql,sizeof(tmp_mysql));
+ net_clear(&mysql->net);
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ DBUG_RETURN(0);
+}
+
+
+/**************************************************************************
+** Change user and database
+**************************************************************************/
+
+my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
+ const char *passwd, const char *db)
+{
+ char buff[512],*pos=buff;
+ DBUG_ENTER("mysql_change_user");
+
+ if (!user)
+ user="";
+ if (!passwd)
+ passwd="";
+
+ pos=strmov(pos,user)+1;
+ pos=scramble(pos, mysql->scramble_buff, passwd,
+ (my_bool) (mysql->protocol_version == 9));
+ pos=strmov(pos+1,db ? db : "");
+ if (simple_command(mysql,COM_CHANGE_USER, buff,(uint) (pos-buff),0))
+ DBUG_RETURN(1);
+
+ my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+
+ mysql->user= my_strdup(user,MYF(MY_WME));
+ mysql->passwd=my_strdup(passwd,MYF(MY_WME));
+ mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0;
+ DBUG_RETURN(0);
+}
+
+
+/**************************************************************************
+** Set current database
+**************************************************************************/
+
+int STDCALL
+mysql_select_db(MYSQL *mysql, const char *db)
+{
+ int error;
+ DBUG_ENTER("mysql_select_db");
+ DBUG_PRINT("enter",("db: '%s'",db));
+
+ if ((error=simple_command(mysql,COM_INIT_DB,db,strlen(db),0)))
+ DBUG_RETURN(error);
+ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->db=my_strdup(db,MYF(MY_WME));
+ DBUG_RETURN(0);
+}
+
+
+/*************************************************************************
+** Send a QUIT to the server and close the connection
+** If handle is alloced by mysql connect free it.
+*************************************************************************/
+
+void STDCALL
+mysql_close(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_close");
+ if (mysql) /* Some simple safety */
+ {
+ if (mysql->net.vio != 0)
+ {
+ free_old_query(mysql);
+ mysql->status=MYSQL_STATUS_READY; /* Force command */
+ simple_command(mysql,COM_QUIT,NullS,0,1);
+ end_server(mysql);
+ }
+ my_free((gptr) mysql->host_info,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.user,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.password,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.unix_socket,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.db,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+ /* Clear pointers for better safety */
+ mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
+ bzero((char*) &mysql->options,sizeof(mysql->options));
+ mysql->net.vio = 0;
+#ifdef HAVE_OPENSSL
+ ((VioConnectorFd*)(mysql->connector_fd))->delete();
+ mysql->connector_fd = 0;
+#endif /* HAVE_OPENSSL */
+ if (mysql->free_me)
+ my_free((gptr) mysql,MYF(0));
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**************************************************************************
+** Do a query. If query returned rows, free old rows.
+** Read data by mysql_store_result or by repeat call of mysql_fetch_row
+**************************************************************************/
+
+int STDCALL
+mysql_query(MYSQL *mysql, const char *query)
+{
+ return mysql_real_query(mysql,query,strlen(query));
+}
+
+
+int STDCALL
+mysql_real_query(MYSQL *mysql, const char *query,uint length)
+{
+ uchar *pos;
+ ulong field_count;
+ MYSQL_DATA *fields;
+ DBUG_ENTER("mysql_real_query");
+ DBUG_PRINT("enter",("handle: %lx",mysql));
+ DBUG_PRINT("query",("Query = \"%s\"",query));
+
+ if (simple_command(mysql,COM_QUERY,query,length,1) ||
+ (length=net_safe_read(mysql)) == packet_error)
+ DBUG_RETURN(-1);
+ free_old_query(mysql); /* Free old result */
+ get_info:
+ pos=(uchar*) mysql->net.read_pos;
+ if ((field_count= net_field_length(&pos)) == 0)
+ {
+ mysql->affected_rows= net_field_length_ll(&pos);
+ mysql->insert_id= net_field_length_ll(&pos);
+ if (pos < mysql->net.read_pos+length && net_field_length(&pos))
+ mysql->info=(char*) pos;
+ DBUG_RETURN(0);
+ }
+ if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
+ {
+ int error=send_file_to_server(mysql,(char*) pos);
+ if ((length=net_safe_read(mysql)) == packet_error || error)
+ DBUG_RETURN(-1);
+ goto get_info; /* Get info packet */
+ }
+ mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
+ if (!(fields=read_rows(mysql,(MYSQL_FIELD*) 0,5)))
+ DBUG_RETURN(-1);
+ if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
+ (uint) field_count,0,
+ (my_bool) test(mysql->server_capabilities &
+ CLIENT_LONG_FLAG))))
+ DBUG_RETURN(-1);
+ mysql->status=MYSQL_STATUS_GET_RESULT;
+ mysql->field_count=field_count;
+ DBUG_RETURN(0);
+}
+
+
+static int
+send_file_to_server(MYSQL *mysql, const char *filename)
+{
+ int fd, readcount;
+ char buf[IO_SIZE*15],*tmp_name;
+ DBUG_ENTER("send_file_to_server");
+
+ fn_format(buf,filename,"","",4); /* Convert to client format */
+ if (!(tmp_name=my_strdup(buf,MYF(0))))
+ {
+ strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY));
+ DBUG_RETURN(-1);
+ }
+ if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0)
+ {
+ mysql->net.last_errno=EE_FILENOTFOUND;
+ sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno);
+ strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1);
+ my_net_write(&mysql->net,"",0); net_flush(&mysql->net);
+ my_free(tmp_name,MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ while ((readcount = (int) my_read(fd,buf,sizeof(buf),MYF(0))) > 0)
+ {
+ if (my_net_write(&mysql->net,buf,readcount))
+ {
+ mysql->net.last_errno=CR_SERVER_LOST;
+ strmov(mysql->net.last_error,ER(mysql->net.last_errno));
+ DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file"));
+ (void) my_close(fd,MYF(0));
+ my_free(tmp_name,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ }
+ (void) my_close(fd,MYF(0));
+ /* Send empty packet to mark end of file */
+ if (my_net_write(&mysql->net,"",0) || net_flush(&mysql->net))
+ {
+ mysql->net.last_errno=CR_SERVER_LOST;
+ sprintf(mysql->net.last_error,ER(mysql->net.last_errno),errno);
+ my_free(tmp_name,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ if (readcount < 0)
+ {
+ mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */
+ sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno);
+ strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1);
+ my_free(tmp_name,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/**************************************************************************
+** Alloc result struct for buffered results. All rows are read to buffer.
+** mysql_data_seek may be used.
+**************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_store_result(MYSQL *mysql)
+{
+ MYSQL_RES *result;
+ DBUG_ENTER("mysql_store_result");
+
+ if (!mysql->fields)
+ DBUG_RETURN(0);
+ if (mysql->status != MYSQL_STATUS_GET_RESULT)
+ {
+ strmov(mysql->net.last_error,
+ ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ DBUG_RETURN(0);
+ }
+ mysql->status=MYSQL_STATUS_READY; /* server is ready */
+ if (!(result=(MYSQL_RES*) my_malloc(sizeof(MYSQL_RES)+
+ sizeof(ulong)*mysql->field_count,
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ mysql->net.last_errno=CR_OUT_OF_MEMORY;
+ strmov(mysql->net.last_error, ER(mysql->net.last_errno));
+ DBUG_RETURN(0);
+ }
+ result->eof=1; /* Marker for buffered */
+ result->lengths=(ulong*) (result+1);
+ if (!(result->data=read_rows(mysql,mysql->fields,mysql->field_count)))
+ {
+ my_free((gptr) result,MYF(0));
+ DBUG_RETURN(0);
+ }
+ mysql->affected_rows= result->row_count= result->data->rows;
+ result->data_cursor= result->data->data;
+ result->fields= mysql->fields;
+ result->field_alloc= mysql->field_alloc;
+ result->field_count= mysql->field_count;
+ result->current_field=0;
+ result->current_row=0; /* Must do a fetch first */
+ mysql->fields=0; /* fields is now in result */
+ DBUG_RETURN(result); /* Data fetched */
+}
+
+
+/**************************************************************************
+** Alloc struct for use with unbuffered reads. Data is fetched by domand
+** when calling to mysql_fetch_row.
+** mysql_data_seek is a noop.
+**
+** No other queries may be specified with the same MYSQL handle.
+** There shouldn't be much processing per row because mysql server shouldn't
+** have to wait for the client (and will not wait more than 30 sec/packet).
+**************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_use_result(MYSQL *mysql)
+{
+ MYSQL_RES *result;
+ DBUG_ENTER("mysql_use_result");
+
+ if (!mysql->fields)
+ DBUG_RETURN(0);
+ if (mysql->status != MYSQL_STATUS_GET_RESULT)
+ {
+ strmov(mysql->net.last_error,
+ ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ DBUG_RETURN(0);
+ }
+ if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
+ sizeof(ulong)*mysql->field_count,
+ MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(0);
+ result->lengths=(ulong*) (result+1);
+ if (!(result->row=(MYSQL_ROW)
+ my_malloc(sizeof(result->row[0])*(mysql->field_count+1), MYF(MY_WME))))
+ { /* Ptrs: to one row */
+ my_free((gptr) result,MYF(0));
+ DBUG_RETURN(0);
+ }
+ result->fields= mysql->fields;
+ result->field_alloc= mysql->field_alloc;
+ result->field_count= mysql->field_count;
+ result->current_field=0;
+ result->handle= mysql;
+ result->current_row= 0;
+ mysql->fields=0; /* fields is now in result */
+ mysql->status=MYSQL_STATUS_USE_RESULT;
+ DBUG_RETURN(result); /* Data is read to be fetched */
+}
+
+
+
+/**************************************************************************
+** Return next field of the query results
+**************************************************************************/
+
+MYSQL_FIELD * STDCALL
+mysql_fetch_field(MYSQL_RES *result)
+{
+ if (result->current_field >= result->field_count)
+ return(NULL);
+ return &result->fields[result->current_field++];
+}
+
+
+/**************************************************************************
+** Return next row of the query results
+**************************************************************************/
+
+MYSQL_ROW STDCALL
+mysql_fetch_row(MYSQL_RES *res)
+{
+ DBUG_ENTER("mysql_fetch_row");
+ if (!res->data)
+ { /* Unbufferred fetch */
+ if (!res->eof)
+ {
+ if (!(read_one_row(res->handle,res->field_count,res->row, res->lengths)))
+ {
+ res->row_count++;
+ DBUG_RETURN(res->current_row=res->row);
+ }
+ else
+ {
+ res->eof=1;
+ res->handle->status=MYSQL_STATUS_READY;
+ }
+ }
+ DBUG_RETURN((MYSQL_ROW) NULL);
+ }
+ {
+ MYSQL_ROW tmp;
+ if (!res->data_cursor)
+ DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
+ tmp = res->data_cursor->data;
+ res->data_cursor = res->data_cursor->next;
+ DBUG_RETURN(res->current_row=tmp);
+ }
+}
+
+/**************************************************************************
+** Get column lengths of the current row
+** If one uses mysql_use_result, res->lengths contains the length information,
+** else the lengths are calculated from the offset between pointers.
+**************************************************************************/
+
+ulong * STDCALL
+mysql_fetch_lengths(MYSQL_RES *res)
+{
+ ulong *lengths,*prev_length;
+ byte *start;
+ MYSQL_ROW column,end;
+
+ if (!(column=res->current_row))
+ return 0; /* Something is wrong */
+ if (res->data)
+ {
+ start=0;
+ prev_length=0; /* Keep gcc happy */
+ lengths=res->lengths;
+ for (end=column+res->field_count+1 ; column != end ; column++,lengths++)
+ {
+ if (!*column)
+ {
+ *lengths=0; /* Null */
+ continue;
+ }
+ if (start) /* Found end of prev string */
+ *prev_length= (uint) (*column-start-1);
+ start= *column;
+ prev_length=lengths;
+ }
+ }
+ return res->lengths;
+}
+
+/**************************************************************************
+** Move to a specific row and column
+**************************************************************************/
+
+void STDCALL
+mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
+{
+ MYSQL_ROWS *tmp=0;
+ DBUG_PRINT("info",("mysql_data_seek(%d)",row));
+ if (result->data)
+ for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
+ result->current_row=0;
+ result->data_cursor = tmp;
+}
+
+/*************************************************************************
+** put the row or field cursor one a position one got from mysql_row_tell()
+** This dosen't restore any data. The next mysql_fetch_row or
+** mysql_fetch_field will return the next row or field after the last used
+*************************************************************************/
+
+MYSQL_ROW_OFFSET STDCALL
+mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET row)
+{
+ MYSQL_ROW_OFFSET return_value=result->data_cursor;
+ result->current_row= 0;
+ result->data_cursor= row;
+ return return_value;
+}
+
+
+MYSQL_FIELD_OFFSET STDCALL
+mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET field_offset)
+{
+ MYSQL_FIELD_OFFSET return_value=result->current_field;
+ result->current_field=field_offset;
+ return return_value;
+}
+
+/*****************************************************************************
+** List all databases
+*****************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_list_dbs(MYSQL *mysql, const char *wild)
+{
+ char buff[255];
+ DBUG_ENTER("mysql_list_dbs");
+
+ append_wild(strmov(buff,"show databases"),buff+sizeof(buff),wild);
+ if (mysql_query(mysql,buff))
+ DBUG_RETURN(0);
+ DBUG_RETURN (mysql_store_result(mysql));
+}
+
+
+/*****************************************************************************
+** List all tables in a database
+** If wild is given then only the tables matching wild is returned
+*****************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_list_tables(MYSQL *mysql, const char *wild)
+{
+ char buff[255];
+ DBUG_ENTER("mysql_list_tables");
+
+ append_wild(strmov(buff,"show tables"),buff+sizeof(buff),wild);
+ if (mysql_query(mysql,buff))
+ DBUG_RETURN(0);
+ DBUG_RETURN (mysql_store_result(mysql));
+}
+
+
+/**************************************************************************
+** List all fields in a table
+** If wild is given then only the fields matching wild is returned
+** Instead of this use query:
+** show fields in 'table' like "wild"
+**************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
+{
+ MYSQL_RES *result;
+ MYSQL_DATA *query;
+ char buff[257],*end;
+ DBUG_ENTER("mysql_list_fields");
+ DBUG_PRINT("enter",("table: '%s' wild: '%s'",table,wild ? wild : ""));
+
+ LINT_INIT(query);
+
+ end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128);
+ if (simple_command(mysql,COM_FIELD_LIST,buff,(uint) (end-buff),1) ||
+ !(query = read_rows(mysql,(MYSQL_FIELD*) 0,6)))
+ DBUG_RETURN(NULL);
+
+ free_old_query(mysql);
+ if (!(result = (MYSQL_RES *) my_malloc(sizeof(MYSQL_RES),
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ free_rows(query);
+ DBUG_RETURN(NULL);
+ }
+ result->field_alloc=mysql->field_alloc;
+ mysql->fields=0;
+ result->field_count = (uint) query->rows;
+ result->fields= unpack_fields(query,&result->field_alloc,
+ result->field_count,1,
+ (my_bool) test(mysql->server_capabilities &
+ CLIENT_LONG_FLAG));
+ result->eof=1;
+ DBUG_RETURN(result);
+}
+
+/* List all running processes (threads) in server */
+
+MYSQL_RES * STDCALL
+mysql_list_processes(MYSQL *mysql)
+{
+ MYSQL_DATA *fields;
+ uint field_count;
+ uchar *pos;
+ DBUG_ENTER("mysql_list_processes");
+
+ LINT_INIT(fields);
+ if (simple_command(mysql,COM_PROCESS_INFO,0,0,0))
+ DBUG_RETURN(0);
+ free_old_query(mysql);
+ pos=(uchar*) mysql->net.read_pos;
+ field_count=(uint) net_field_length(&pos);
+ if (!(fields = read_rows(mysql,(MYSQL_FIELD*) 0,5)))
+ DBUG_RETURN(NULL);
+ if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0,
+ (my_bool) test(mysql->server_capabilities &
+ CLIENT_LONG_FLAG))))
+ DBUG_RETURN(0);
+ mysql->status=MYSQL_STATUS_GET_RESULT;
+ mysql->field_count=field_count;
+ DBUG_RETURN(mysql_store_result(mysql));
+}
+
+
+int STDCALL
+mysql_create_db(MYSQL *mysql, const char *db)
+{
+ DBUG_ENTER("mysql_createdb");
+ DBUG_PRINT("enter",("db: %s",db));
+ DBUG_RETURN(simple_command(mysql,COM_CREATE_DB,db, (uint) strlen(db),0));
+}
+
+
+int STDCALL
+mysql_drop_db(MYSQL *mysql, const char *db)
+{
+ DBUG_ENTER("mysql_drop_db");
+ DBUG_PRINT("enter",("db: %s",db));
+ DBUG_RETURN(simple_command(mysql,COM_DROP_DB,db,(uint) strlen(db),0));
+}
+
+
+int STDCALL
+mysql_shutdown(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_shutdown");
+ DBUG_RETURN(simple_command(mysql,COM_SHUTDOWN,0,0,0));
+}
+
+
+int STDCALL
+mysql_refresh(MYSQL *mysql,uint options)
+{
+ uchar bits[1];
+ DBUG_ENTER("mysql_refresh");
+ bits[0]= (uchar) options;
+ DBUG_RETURN(simple_command(mysql,COM_REFRESH,(char*) bits,1,0));
+}
+
+int STDCALL
+mysql_kill(MYSQL *mysql,ulong pid)
+{
+ char buff[12];
+ DBUG_ENTER("mysql_kill");
+ int4store(buff,pid);
+ DBUG_RETURN(simple_command(mysql,COM_PROCESS_KILL,buff,4,0));
+}
+
+
+int STDCALL
+mysql_dump_debug_info(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_dump_debug_info");
+ DBUG_RETURN(simple_command(mysql,COM_DEBUG,0,0,0));
+}
+
+char * STDCALL
+mysql_stat(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_stat");
+ if (simple_command(mysql,COM_STATISTICS,0,0,0))
+ return mysql->net.last_error;
+ mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
+ if (!mysql->net.read_pos[0])
+ {
+ mysql->net.last_errno=CR_WRONG_HOST_INFO;
+ strmov(mysql->net.last_error, ER(mysql->net.last_errno));
+ return mysql->net.last_error;
+ }
+ DBUG_RETURN((char*) mysql->net.read_pos);
+}
+
+
+int STDCALL
+mysql_ping(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_ping");
+ DBUG_RETURN(simple_command(mysql,COM_PING,0,0,0));
+}
+
+
+char * STDCALL
+mysql_get_server_info(MYSQL *mysql)
+{
+ return((char*) mysql->server_version);
+}
+
+
+char * STDCALL
+mysql_get_host_info(MYSQL *mysql)
+{
+ return(mysql->host_info);
+}
+
+
+uint STDCALL
+mysql_get_proto_info(MYSQL *mysql)
+{
+ return (mysql->protocol_version);
+}
+
+char * STDCALL
+mysql_get_client_info(void)
+{
+ return (char*) MYSQL_SERVER_VERSION;
+}
+
+
+int STDCALL
+mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
+{
+ DBUG_ENTER("mysql_option");
+ DBUG_PRINT("enter",("option: %d",(int) option));
+ switch (option) {
+ case MYSQL_OPT_CONNECT_TIMEOUT:
+ mysql->options.connect_timeout= *(uint*) arg;
+ break;
+ case MYSQL_OPT_COMPRESS:
+ mysql->options.compress=1; /* Remember for connect */
+ break;
+ case MYSQL_OPT_NAMED_PIPE:
+ mysql->options.named_pipe=1; /* Force named pipe */
+ break;
+ case MYSQL_INIT_COMMAND:
+ my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.init_command=my_strdup(arg,MYF(MY_WME));
+ break;
+ case MYSQL_READ_DEFAULT_FILE:
+ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.my_cnf_file=my_strdup(arg,MYF(MY_WME));
+ break;
+ case MYSQL_READ_DEFAULT_GROUP:
+ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.my_cnf_group=my_strdup(arg,MYF(MY_WME));
+ break;
+ default:
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
+
+/****************************************************************************
+** Functions to get information from the MySQL structure
+** These are functions to make shared libraries more usable.
+****************************************************************************/
+
+/* MYSQL_RES */
+my_ulonglong mysql_num_rows(MYSQL_RES *res)
+{
+ return res->row_count;
+}
+
+unsigned int mysql_num_fields(MYSQL_RES *res)
+{
+ return res->field_count;
+}
+
+my_bool mysql_eof(MYSQL_RES *res)
+{
+ return res->eof;
+}
+
+MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr)
+{
+ return &(res)->fields[fieldnr];
+}
+
+MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res)
+{
+ return (res)->fields;
+}
+
+MYSQL_ROWS *mysql_row_tell(MYSQL_RES *res)
+{
+ return res->data_cursor;
+}
+
+uint mysql_field_tell(MYSQL_RES *res)
+{
+ return (res)->current_field;
+}
+
+/* MYSQL */
+
+unsigned int mysql_field_count(MYSQL *mysql)
+{
+ return mysql->field_count;
+}
+
+my_ulonglong mysql_affected_rows(MYSQL *mysql)
+{
+ return (mysql)->affected_rows;
+}
+
+my_ulonglong mysql_insert_id(MYSQL *mysql)
+{
+ return (mysql)->insert_id;
+}
+
+uint mysql_errno(MYSQL *mysql)
+{
+ return (mysql)->net.last_errno;
+}
+
+char *mysql_error(MYSQL *mysql)
+{
+ return (mysql)->net.last_error;
+}
+
+char *mysql_info(MYSQL *mysql)
+{
+ return (mysql)->info;
+}
+
+ulong mysql_thread_id(MYSQL *mysql)
+{
+ return (mysql)->thread_id;
+}
+
+/****************************************************************************
+** Some support functions
+****************************************************************************/
+
+/*
+** Add escape characters to a string (blob?) to make it suitable for a insert
+** to should at least have place for length*2+1 chars
+** Returns the length of the to string
+*/
+
+ulong STDCALL
+mysql_escape_string(char *to,const char *from,ulong length)
+{
+ const char *to_start=to;
+ const char *end;
+ for (end=from+length; from != end ; from++)
+ {
+#ifdef USE_MB
+ int l;
+ if ((l = ismbchar(from, end)))
+ {
+ while (l--)
+ *to++ = *from++;
+ from--;
+ continue;
+ }
+#endif
+ switch (*from) {
+ case 0: /* Must be escaped for 'mysql' */
+ *to++= '\\';
+ *to++= '0';
+ break;
+ case '\n': /* Must be escaped for logs */
+ *to++= '\\';
+ *to++= 'n';
+ break;
+ case '\r':
+ *to++= '\\';
+ *to++= 'r';
+ break;
+ case '\\':
+ *to++= '\\';
+ *to++= '\\';
+ break;
+ case '\'':
+ *to++= '\\';
+ *to++= '\'';
+ break;
+ case '"': /* Better safe than sorry */
+ *to++= '\\';
+ *to++= '"';
+ break;
+ case '\032': /* This gives problems on Win32 */
+ *to++= '\\';
+ *to++= 'Z';
+ break;
+ default:
+ *to++= *from;
+ }
+ }
+ *to=0;
+ return (ulong) (to-to_start);
+}
+
+
+char * STDCALL
+mysql_odbc_escape_string(char *to, ulong to_length,
+ const char *from, ulong from_length,
+ void *param,
+ char * (*extend_buffer)
+ (void *, char *, ulong *))
+{
+ char *to_end=to+to_length-5;
+ const char *end;
+
+ for (end=from+from_length; from != end ; from++)
+ {
+ if (to >= to_end)
+ {
+ to_length = (ulong) (end-from)+512; /* We want this much more */
+ if (!(to=(*extend_buffer)(param, to, &to_length)))
+ return to;
+ to_end=to+to_length-5;
+ }
+#ifdef USE_MB
+ {
+ int l;
+ if ((l = ismbchar(from, end)))
+ {
+ while (l--)
+ *to++ = *from++;
+ from--;
+ continue;
+ }
+ }
+#endif
+ switch (*from) {
+ case 0: /* Must be escaped for 'mysql' */
+ *to++= '\\';
+ *to++= '0';
+ break;
+ case '\n': /* Must be escaped for logs */
+ *to++= '\\';
+ *to++= 'n';
+ break;
+ case '\r':
+ *to++= '\\';
+ *to++= 'r';
+ break;
+ case '\\':
+ *to++= '\\';
+ *to++= '\\';
+ break;
+ case '\'':
+ *to++= '\\';
+ *to++= '\'';
+ break;
+ case '"': /* Better safe than sorry */
+ *to++= '\\';
+ *to++= '"';
+ break;
+ case '\032': /* This gives problems on Win32 */
+ *to++= '\\';
+ *to++= 'Z';
+ break;
+ default:
+ *to++= *from;
+ }
+ }
+ return to;
+}
+
+
+void STDCALL
+myodbc_remove_escape(char *name)
+{
+ char *to;
+#ifdef USE_MB
+ char *end;
+ for (end=name; *end ; end++) ;
+#endif
+
+ for (to=name ; *name ; name++)
+ {
+#ifdef USE_MB
+ int l;
+ if( (l = ismbchar( name , end ) ) ) {
+ while (l--)
+ *to++ = *name++;
+ name--;
+ continue;
+ }
+#endif
+ if (*name == '\\' && name[1])
+ name++;
+ *to++= *name;
+ }
+ *to=0;
+}
diff --git a/client/Attic/net.c b/client/Attic/net.c
new file mode 100644
index 00000000000..4ea3f002bbc
--- /dev/null
+++ b/client/Attic/net.c
@@ -0,0 +1,628 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Write and read of logical packets to/from socket
+** Writes are cached into net_buffer_length big packets.
+** Read packets are reallocated dynamicly when reading big packets.
+** Each logical packet has the following pre-info:
+** 3 byte length & 1 byte package-number.
+*/
+
+#ifdef _WIN32
+#include <winsock.h>
+#endif
+#include <global.h>
+#include <violite.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <violite.h>
+
+#if !defined(__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 thread_safe_add
+#define thread_safe_add(A,B,C)
+#endif
+
+/*
+** Give error if a too big packet is found
+** The server can change this with the -O switch, but because the client
+** can't normally do this the client should have a bigger max-buffer.
+*/
+
+#ifdef MYSQL_SERVER
+ulong max_allowed_packet=65536;
+extern uint test_flags;
+#else
+ulong max_allowed_packet=16*1024*1024L;
+#endif
+ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
+
+#define TEST_BLOCKING 8
+static int net_write_buff(NET *net,const char *packet,uint len);
+
+
+ /* Init with packet info */
+
+int my_net_init(NET *net, Vio* vio)
+{
+ if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME))))
+ return 1;
+ if (net_buffer_length > max_allowed_packet)
+ max_allowed_packet=net_buffer_length;
+ net->buff_end=net->buff+(net->max_packet=net_buffer_length);
+ net->vio = vio;
+ net->error=0; net->return_errno=0; net->return_status=0;
+ net->timeout=NET_READ_TIMEOUT; /* Timeout for read */
+ net->pkt_nr=0;
+ net->write_pos=net->read_pos = net->buff;
+ net->last_error[0]=0;
+ net->compress=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 (%ld)", length));
+#ifdef MYSQL_SERVER
+ sql_print_error("Packet too large (%ld)\n", length);
+#else
+ fprintf(stderr,"Packet too large (%ld)\n", length);
+#endif
+ net->error=1;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_PACKET_TOO_LARGE;
+#endif
+ return 1;
+ }
+ pkt_length = (length+IO_SIZE-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,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,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;
+ thread_safe_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
+*****************************************************************************/
+
+
+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;
+ thread_safe_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ }
+ if (i == 0)
+ { /* First parts is packet length */
+ ulong helping;
+ if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
+ {
+ if (net->buff[net->where_b] != (uchar) 255)
+ {
+ DBUG_PRINT("error",
+ ("Packets out of order (Found: %d, expected %d)",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr));
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,"Packets out of order (Found: %d, expected %d)\n",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr);
+#endif
+ }
+ len= packet_error;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
+#endif
+ goto end;
+ }
+ net->pkt_nr++;
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ {
+ /* complen is > 0 if package is really compressed */
+ *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
+ }
+#endif
+
+ len=uint3korr(net->buff+net->where_b);
+ helping = max(len,*complen) + net->where_b;
+ /* The necessary size of net->buff */
+ if (helping >= net->max_packet)
+ {
+ /* We must allocate one extra byte for the end null */
+ if (net_realloc(net,helping+1))
+ {
+ 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/client/Makefile.am b/client/Makefile.am
new file mode 100644
index 00000000000..e715a2c15d0
--- /dev/null
+++ b/client/Makefile.am
@@ -0,0 +1,43 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; 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
+
+INCLUDES = -I$(srcdir)/../include \
+ -I../include -I$(srcdir)/.. -I$(top_srcdir) \
+ -I..
+LIBS = @CLIENT_LIBS@
+LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysql/libmysqlclient.la
+bin_PROGRAMS = mysql mysqladmin mysqlshow mysqldump mysqlimport
+noinst_PROGRAMS = insert_test select_test thread_test mysql-test
+noinst_HEADERS = sql_string.h completion_hash.h my_readline.h
+mysql_SOURCES = mysql.cc readline.cc sql_string.cc completion_hash.cc
+mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) $(CXXLDFLAGS)
+mysql_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+mysqladmin_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+mysqlshow_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+mysqldump_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+mysqlimport_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+insert_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+select_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+mysql_test_SOURCES= mysql-test.c
+mysql_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+
+# Fix for mit-threads
+DEFS = -DUNDEF_THREADS_HACK
+
+thread_test.o: thread_test.c
+ $(COMPILE) -c @MT_INCLUDES@ $(INCLUDES) $<
diff --git a/client/completion_hash.cc b/client/completion_hash.cc
new file mode 100644
index 00000000000..006427f0295
--- /dev/null
+++ b/client/completion_hash.cc
@@ -0,0 +1,249 @@
+/* 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 */
+
+/* Quick & light hash implementation for tab completion purposes
+ *
+ * by Andi Gutmans <andi@zend.com>
+ * and Zeev Suraski <zeev@zend.com>
+ * Small portability changes by Monty. Changed also to use my_malloc/my_free
+ */
+
+#include <global.h>
+#include <m_string.h>
+#undef SAFEMALLOC // Speed things up
+#include <my_sys.h>
+#include "completion_hash.h"
+
+uint hashpjw(char *arKey, uint nKeyLength)
+{
+ uint h = 0, g, i;
+
+ for (i = 0; i < nKeyLength; i++) {
+ h = (h << 4) + arKey[i];
+ if ((g = (h & 0xF0000000))) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ return h;
+}
+
+int completion_hash_init(HashTable *ht, uint nSize)
+{
+ ht->arBuckets = (Bucket **) my_malloc(nSize* sizeof(Bucket *),
+ MYF(MY_ZEROFILL | MY_WME));
+
+ if (!ht->arBuckets) {
+ ht->initialized = 0;
+ return FAILURE;
+ }
+ ht->pHashFunction = hashpjw;
+ ht->nTableSize = nSize;
+ ht->initialized = 1;
+ return SUCCESS;
+}
+
+
+int completion_hash_update(HashTable *ht, char *arKey, uint nKeyLength,
+ char *str)
+{
+ uint h, nIndex;
+
+ Bucket *p;
+
+ h = ht->pHashFunction(arKey, nKeyLength);
+ nIndex = h % ht->nTableSize;
+
+ if (nKeyLength <= 0) {
+ return FAILURE;
+ }
+ p = ht->arBuckets[nIndex];
+ while (p)
+ {
+ if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
+ if (!memcmp(p->arKey, arKey, nKeyLength)) {
+ entry *n;
+
+ n = (entry *) my_malloc(sizeof(entry),
+ MYF(MY_WME));
+ n->pNext = p->pData;
+ n->str = str;
+ p->pData = n;
+ p->count++;
+
+ return SUCCESS;
+ }
+ }
+ p = p->pNext;
+ }
+
+ p = (Bucket *) my_malloc(sizeof(Bucket),MYF(MY_WME));
+
+ if (!p) {
+ return FAILURE;
+ }
+ p->arKey = arKey;
+ p->nKeyLength = nKeyLength;
+ p->h = h;
+
+ p->pData = (entry*) my_malloc(sizeof(entry),MYF(MY_WME));
+ if (!p->pData) {
+ my_free((gptr) p,MYF(0));
+ return FAILURE;
+ }
+ p->pData->str = str;
+ p->pData->pNext = 0;
+ p->count = 1;
+
+ p->pNext = ht->arBuckets[nIndex];
+ ht->arBuckets[nIndex] = p;
+
+ return SUCCESS;
+}
+
+static Bucket *completion_hash_find(HashTable *ht, char *arKey,
+ uint nKeyLength)
+{
+ uint h, nIndex;
+ Bucket *p;
+
+ h = ht->pHashFunction(arKey, nKeyLength);
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p)
+ {
+ if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
+ if (!memcmp(p->arKey, arKey, nKeyLength)) {
+ return p;
+ }
+ }
+ p = p->pNext;
+ }
+ return (Bucket*) 0;
+}
+
+
+int completion_hash_exists(HashTable *ht, char *arKey, uint nKeyLength)
+{
+ uint h, nIndex;
+ Bucket *p;
+
+ h = ht->pHashFunction(arKey, nKeyLength);
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p)
+ {
+ if ((p->h == h) && (p->nKeyLength == nKeyLength))
+ {
+ if (!strcmp(p->arKey, arKey)) {
+ return 1;
+ }
+ }
+ p = p->pNext;
+ }
+ return 0;
+}
+
+Bucket *find_all_matches(HashTable *ht, char *str, uint length,
+ uint *res_length)
+{
+ Bucket *b;
+
+ b = completion_hash_find(ht,str,length);
+ if (!b) {
+ *res_length = 0;
+ return (Bucket*) 0;
+ } else {
+ *res_length = length;
+ return b;
+ }
+}
+
+Bucket *find_longest_match(HashTable *ht, char *str, uint length,
+ uint *res_length)
+{
+ Bucket *b,*return_b;
+ char *s;
+ uint count;
+ uint lm;
+
+ b = completion_hash_find(ht,str,length);
+ if (!b) {
+ *res_length = 0;
+ return (Bucket*) 0;
+ }
+
+ count = b->count;
+ lm = length;
+ s = b->pData->str;
+
+ return_b = b;
+ while (s[lm]!=0 && (b=completion_hash_find(ht,s,lm+1))) {
+ if (b->count<count) {
+ *res_length=lm;
+ return return_b;
+ }
+ return_b=b;
+ lm++;
+ }
+ *res_length=lm;
+ return return_b;
+}
+
+
+void completion_hash_clean(HashTable *ht)
+{
+ uint i;
+ entry *e, *t;
+ Bucket *b, *tmp;
+
+ for (i=0; i<ht->nTableSize; i++) {
+ b = ht->arBuckets[i];
+ while (b) {
+ e = b->pData;
+ while (e) {
+ t = e;
+ e = e->pNext;
+ my_free((gptr) t,MYF(0));
+ }
+ tmp = b;
+ b = b->pNext;
+ my_free((gptr) tmp,MYF(0));
+ }
+ }
+ bzero((char*) ht->arBuckets,ht->nTableSize*sizeof(Bucket *));
+}
+
+
+void completion_hash_free(HashTable *ht)
+{
+ completion_hash_clean(ht);
+ my_free((gptr) ht->arBuckets,MYF(0));
+}
+
+
+void add_word(HashTable *ht,char *str)
+{
+ int i;
+ int length= (int) strlen(str);
+
+ for (i=1; i<=length; i++) {
+ completion_hash_update(ht, str, i, str);
+ }
+}
diff --git a/client/completion_hash.h b/client/completion_hash.h
new file mode 100644
index 00000000000..583a42bbbe5
--- /dev/null
+++ b/client/completion_hash.h
@@ -0,0 +1,57 @@
+/* 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 */
+
+#ifndef _HASH_
+#define _HASH_
+
+#define SUCCESS 0
+#define FAILURE 1
+
+#include <sys/types.h>
+
+typedef struct _entry {
+ char *str;
+ struct _entry *pNext;
+} entry;
+
+typedef struct bucket {
+ uint h; /* Used for numeric indexing */
+ char *arKey;
+ uint nKeyLength;
+ uint count;
+ entry *pData;
+ struct bucket *pNext;
+} Bucket;
+
+typedef struct hashtable {
+ uint nTableSize;
+ uint initialized;
+ uint(*pHashFunction) (char *arKey, uint nKeyLength);
+ Bucket **arBuckets;
+} HashTable;
+
+extern int completion_hash_init(HashTable *ht, uint nSize);
+extern int completion_hash_update(HashTable *ht, char *arKey, uint nKeyLength, char *str);
+extern int hash_exists(HashTable *ht, char *arKey);
+extern Bucket *find_all_matches(HashTable *ht, char *str, uint length, uint *res_length);
+extern Bucket *find_longest_match(HashTable *ht, char *str, uint length, uint *res_length);
+extern void add_word(HashTable *ht,char *str);
+extern void completion_hash_clean(HashTable *ht);
+extern int completion_hash_exists(HashTable *ht, char *arKey, uint nKeyLength);
+extern void completion_hash_free(HashTable *ht);
+
+#endif /* _HASH_ */
diff --git a/client/connect_test.c b/client/connect_test.c
new file mode 100644
index 00000000000..661d448fdb0
--- /dev/null
+++ b/client/connect_test.c
@@ -0,0 +1,66 @@
+/* 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 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "mysql.h"
+
+static void change_user(MYSQL *sock,const char *user, const char *password,
+ const char *db,my_bool warning)
+{
+ if (mysql_change_user(sock,user,password,db) != warning)
+ {
+ fprintf(stderr,"Couldn't change user to: user: '%s', password: '%s', db: '%s': Error: %s\n",
+ user, password ? password : "", db ? db : "",
+ mysql_error(sock));
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ MYSQL *sock;
+
+ if (!(sock=mysql_init(0)))
+ {
+ fprintf(stderr,"Couldn't initialize mysql struct\n");
+ exit(1);
+ }
+ mysql_options(sock,MYSQL_READ_DEFAULT_GROUP,"connect");
+ if (!mysql_real_connect(sock,NULL,NULL,NULL,NULL,0,NULL,0))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n",mysql_error(sock));
+ perror("");
+ exit(1);
+ }
+
+ if (mysql_select_db(sock,"test"))
+ {
+ fprintf(stderr,"Couldn't select database test: Error: %s\n",
+ mysql_error(sock));
+ }
+
+ change_user(sock,"test_user","test_user","test",0);
+ change_user(sock,"test",NULL,"test",0);
+ change_user(sock,"test_user",NULL,"test",1);
+ change_user(sock,"test_user",NULL,NULL,1);
+ change_user(sock,"test_user","test_user","mysql",1);
+
+ mysql_close(sock);
+ exit(0);
+ return 0;
+}
diff --git a/client/errmsg.c b/client/errmsg.c
new file mode 100644
index 00000000000..e269f77ee36
--- /dev/null
+++ b/client/errmsg.c
@@ -0,0 +1,93 @@
+/* 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 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)"
+};
+
+#else /* ENGLISH */
+const char *client_errors[]=
+{
+ "Unknown MySQL error",
+ "Can't create UNIX socket (%d)",
+ "Can't connect to local MySQL server through socket '%-.64s' (%d)",
+ "Can't connect to MySQL server on '%-.64s' (%d)",
+ "Can't create TCP/IP socket (%d)",
+ "Unknown MySQL Server Host '%-.64s' (%d)",
+ "MySQL server has gone away",
+ "Protocol mismatch. Server Version = %d Client Version = %d",
+ "MySQL client run out of memory",
+ "Wrong host info",
+ "Localhost via UNIX socket",
+ "%s via TCP/IP",
+ "Error in server handshake",
+ "Lost connection to MySQL server during query",
+ "Commands out of sync; You can't run this command now",
+ "%s via named pipe",
+ "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)",
+ "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)",
+ "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)",
+};
+#endif
+
+
+void init_client_errs(void)
+{
+ errmsg[CLIENT_ERRMAP] = &client_errors[0];
+}
diff --git a/client/get_password.c b/client/get_password.c
new file mode 100644
index 00000000000..25069a14b75
--- /dev/null
+++ b/client/get_password.c
@@ -0,0 +1,214 @@
+/* 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/client/insert_test.c b/client/insert_test.c
new file mode 100644
index 00000000000..640935d63b2
--- /dev/null
+++ b/client/insert_test.c
@@ -0,0 +1,65 @@
+/* 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 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "mysql.h"
+
+#define INSERT_QUERY "insert into test (name,num) values ('item %d', %d)"
+
+
+int main(int argc, char **argv)
+{
+ int count,num;
+ MYSQL *sock,mysql;
+ char qbuf[160];
+
+ if (argc != 3)
+ {
+ fprintf(stderr,"usage : insert_test <dbname> <Num>\n\n");
+ exit(1);
+ }
+
+ if (!(sock = mysql_connect(&mysql,NULL,0,0)))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n",mysql_error(&mysql));
+ perror("");
+ exit(1);
+ }
+
+ if (mysql_select_db(sock,argv[1]))
+ {
+ fprintf(stderr,"Couldn't select database %s!\n%s\n",argv[1],
+ mysql_error(sock));
+ }
+
+ num = atoi(argv[2]);
+ count = 0;
+ while (count < num)
+ {
+ sprintf(qbuf,INSERT_QUERY,count,count);
+ if(mysql_query(sock,qbuf))
+ {
+ fprintf(stderr,"Query failed (%s)\n",mysql_error(sock));
+ exit(1);
+ }
+ count++;
+ }
+ mysql_close(sock);
+ exit(0);
+ return 0;
+}
diff --git a/client/list_test.c b/client/list_test.c
new file mode 100644
index 00000000000..718cc45e012
--- /dev/null
+++ b/client/list_test.c
@@ -0,0 +1,86 @@
+/* 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 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 */
+
+#ifdef __WIN__
+#include <windows.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include "mysql.h"
+
+#define SELECT_QUERY "select name from test where num = %d"
+
+
+int main(int argc, char **argv)
+{
+ int count, num;
+ MYSQL mysql,*sock;
+ MYSQL_RES *res;
+ char qbuf[160];
+
+ if (argc != 2)
+ {
+ fprintf(stderr,"usage : select_test <dbname>\n\n");
+ exit(1);
+ }
+
+ if (!(sock = mysql_connect(&mysql,NULL,0,0)))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n\n",mysql_error(&mysql));
+ perror("");
+ exit(1);
+ }
+
+ if (mysql_select_db(sock,argv[1]) < 0)
+ {
+ fprintf(stderr,"Couldn't select database %s!\n%s\n",argv[1],
+ mysql_error(sock));
+ exit(1);
+ }
+
+ if (!(res=mysql_list_dbs(sock,NULL)))
+ {
+ fprintf(stderr,"Couldn't list dbs!\n%s\n",mysql_error(sock));
+ exit(1);
+ }
+ mysql_free_result(res);
+ if (!(res=mysql_list_tables(sock,NULL)))
+ {
+ fprintf(stderr,"Couldn't list tables!\n%s\n",mysql_error(sock));
+ exit(1);
+ }
+ mysql_free_result(res);
+
+ mysql_close(sock);
+ exit(0);
+ return 0;
+}
diff --git a/client/my_readline.h b/client/my_readline.h
new file mode 100644
index 00000000000..c9a0e863870
--- /dev/null
+++ b/client/my_readline.h
@@ -0,0 +1,34 @@
+/* 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 */
+
+/* readline for batch mode */
+
+typedef struct st_line_buffer
+{
+ File file;
+ char *buffer; /* The buffer itself, grown as needed. */
+ char *end; /* Pointer at buffer end */
+ char *start_of_line,*end_of_line;
+ uint bufread; /* Number of bytes to get with each read(). */
+ uint eof;
+ ulong max_size;
+} LINE_BUFFER;
+
+extern LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file);
+extern LINE_BUFFER *batch_readline_command(my_string str);
+extern char *batch_readline(LINE_BUFFER *buffer);
+extern void batch_readline_end(LINE_BUFFER *buffer);
diff --git a/client/mysql.cc b/client/mysql.cc
new file mode 100644
index 00000000000..2636b49cd83
--- /dev/null
+++ b/client/mysql.cc
@@ -0,0 +1,2060 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* mysql command tool
+ * Commands compatible with mSQL by David J. Hughes
+ *
+ * Written by:
+ * Michael 'Monty' Widenius
+ * Andi Gutmans <andi@zend.com>
+ * Zeev Suraski <zeev@zend.com>
+ *
+ **/
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+#include "errmsg.h"
+#include <my_dir.h>
+#ifndef __GNU_LIBRARY__
+#define __GNU_LIBRARY__ // Skipp warnings in getopt.h
+#endif
+#include <getopt.h>
+#include "my_readline.h"
+#include <signal.h>
+
+gptr sql_alloc(unsigned size); // Don't use mysqld alloc for theese
+void sql_element_free(void *ptr);
+#include "sql_string.h"
+
+extern "C" {
+#if defined(HAVE_CURSES_H) && defined(HAVE_TERM_H)
+#include <curses.h>
+#include <term.h>
+#else
+#if defined(HAVE_TERMIOS_H)
+#include <termios.h>
+#include <unistd.h>
+#elif defined(HAVE_TERMBITS_H)
+#include <termbits.h>
+#elif defined(HAVE_ASM_TERMBITS_H) && (!defined __GLIBC__ || !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ > 0))
+#include <asm/termbits.h> // Standard linux
+#endif
+#undef VOID
+#if defined(HAVE_TERMCAP_H)
+#include <termcap.h>
+#else
+#ifdef HAVE_CURSES_H
+#include <curses.h>
+#endif
+#undef SYSV // hack to avoid syntax error
+#ifdef HAVE_TERM_H
+#include <term.h>
+#endif
+#endif
+#endif
+
+#undef bcmp // Fix problem with new readline
+#undef bzero
+#ifdef __WIN__
+#include <conio.h>
+#else
+#include <readline/readline.h>
+#define HAVE_READLINE
+#endif
+ //int vidattr(long unsigned int attrs); // Was missing in sun curses
+}
+
+#if !defined(HAVE_VIDATTR)
+#undef vidattr
+#define vidattr(A) {} // Can't get this to work
+#endif
+
+#ifdef __WIN__
+#define cmp_database(A,B) my_strcasecmp((A),(B))
+#else
+#define cmp_database(A,B) strcmp((A),(B))
+#endif
+
+#include "completion_hash.h"
+
+typedef struct st_status
+{
+ int exit_status;
+ ulong query_start_line;
+ char *file_name;
+ LINE_BUFFER *line_buff;
+ bool batch,add_to_history;
+} STATUS;
+
+
+static HashTable ht;
+
+enum enum_info_type { INFO_INFO,INFO_ERROR,INFO_RESULT};
+typedef enum enum_info_type INFO_TYPE;
+
+static MYSQL mysql; /* The connection */
+static bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0,
+ connected=0,opt_raw_data=0,unbuffered=0,output_tables=0,
+ no_rehash=0,skip_updates=0,safe_updates=0,one_database=0,
+ opt_compress=0,
+ vertical=0,skip_line_numbers=0,skip_column_names=0,opt_html=0,
+ no_named_cmds=0;
+static uint verbose=0,opt_silent=0,opt_mysql_port=0;
+static my_string opt_mysql_unix_port=0;
+static int connect_flag=CLIENT_INTERACTIVE;
+static char *current_host,*current_db,*current_user=0,*opt_password=0,
+ *default_charset;
+static char *histfile;
+static String glob_buffer,old_buffer;
+static STATUS status;
+static ulong select_limit,max_join_size;
+
+#include "sslopt-vars.h"
+
+#ifndef DBUG_OFF
+const char *default_dbug_option="d:t:o,/tmp/mysql.trace";
+#endif
+
+/* The names of functions that actually do the manipulation. */
+static int get_options(int argc,char **argv);
+static int com_quit(String *str,char*),
+ com_go(String *str,char*), com_ego(String *str,char*),
+ com_edit(String *str,char*), com_print(String *str,char*),
+ com_help(String *str,char*), com_clear(String *str,char*),
+ com_connect(String *str,char*), com_status(String *str,char*),
+ com_use(String *str,char*), com_source(String *str, char*),
+ com_rehash(String *str, char*);
+
+static int read_lines(bool execute_commands);
+static int sql_connect(char *host,char *database,char *user,char *password,
+ uint silent);
+static int put_info(const char *str,INFO_TYPE info,uint error=0);
+static void safe_put_field(const char *pos,ulong length);
+
+/* A structure which contains information on the commands this program
+ can understand. */
+
+typedef struct {
+ const char *name; /* User printable name of the function. */
+ char cmd_char; /* msql command character */
+ int (*func)(String *str,char *); /* Function to call to do the job. */
+ bool takes_params; /* Max parameters for command */
+ const char *doc; /* Documentation for this function. */
+} COMMANDS;
+
+static COMMANDS commands[] = {
+ { "help", 'h',com_help, 0,"Display this text" },
+ { "?", 'h',com_help, 0,"Synonym for `help'" },
+ { "clear",'c',com_clear,0,"Clear command"},
+ { "connect",'r',com_connect,1,
+ "Reconnect to the server. Optional arguments are db and host" },
+ { "edit", 'e',com_edit, 0,"Edit command with $EDITOR"},
+ { "exit", 'q', com_quit, 0,"Exit mysql. Same as quit"},
+ { "go", 'g',com_go, 0,"Send command to mysql server" },
+ { "ego", 'G',com_ego, 0,
+ "Send command to mysql server; Display result vertically"},
+ { "print",'p',com_print,0,"Print current command" },
+ { "quit", 'q',com_quit, 0,"Quit mysql" },
+ { "rehash", '#', com_rehash, 0, "Rebuild completion hash" },
+ { "source", '.', com_source, 1,
+ "Execute a SQL script file. Takes a file name as an argument"},
+
+ { "status",'s',com_status,0,"Get status information from the server"},
+ { "use",'u',com_use,1,
+ "Use another database. Takes database name as argument" },
+
+ { "create table",0,0,0,""}, /* Get bash expansion for some commmands */
+ { "create database",0,0,0,""},
+ { "drop",0,0,0,""},
+ { "select",0,0,0,""},
+ { "insert",0,0,0,""},
+ { "replace",0,0,0,""},
+ { "update",0,0,0,""},
+ { "delete",0,0,0,""},
+ { "explain",0,0,0,""},
+ { "show databases",0,0,0,""},
+ { "show fields from",0,0,0,""},
+ { "show keys from",0,0,0,""},
+ { "show tables",0,0,0,""},
+ { "load data from",0,0,0,""},
+ { "alter table",0,0,0,""},
+ { "set option",0,0,0,""},
+ { "lock tables",0,0,0,""},
+ { "unlock tables",0,0,0,""},
+ { (char *)NULL, 0,0,0,""},
+};
+
+static const char *load_default_groups[]= { "mysql","client",0 };
+
+#ifdef HAVE_READLINE
+extern "C" void add_history(char *command); /* From readline directory */
+extern "C" int read_history(char *command);
+extern "C" int write_history(char *command);
+static void initialize_readline (char *name);
+#endif
+
+static COMMANDS *find_command (char *name,char cmd_name);
+static bool add_line(String &buffer,char *line,char *in_string);
+static void remove_cntrl(String &buffer);
+static void print_table_data(MYSQL_RES *result);
+static void print_table_data_html(MYSQL_RES *result);
+static void print_tab_data(MYSQL_RES *result);
+static void print_table_data_vertically(MYSQL_RES *result);
+static ulong start_timer(void);
+static void end_timer(ulong start_time,char *buff);
+static void mysql_end_timer(ulong start_time,char *buff);
+static void nice_time(double sec,char *buff,bool part_second);
+static sig_handler mysql_end(int sig);
+
+
+int main(int argc,char *argv[])
+{
+ char buff[80];
+
+ MY_INIT(argv[0]);
+ DBUG_ENTER("main");
+ DBUG_PROCESS(argv[0]);
+
+ if (!isatty(0) || !isatty(1))
+ {
+ status.batch=1; opt_silent=1;
+ ignore_errors=0;
+ }
+ else
+ status.add_to_history=1;
+ status.exit_status=1;
+ load_defaults("my",load_default_groups,&argc,&argv);
+ if (get_options(argc,(char **) argv))
+ {
+ my_end(0);
+ exit(1);
+ }
+ free_defaults(argv);
+ if (status.batch && !status.line_buff &&
+ !(status.line_buff=batch_readline_init(max_allowed_packet+512,stdin)))
+ exit(1);
+ glob_buffer.realloc(512);
+ completion_hash_init(&ht,50);
+ if (sql_connect(current_host,current_db,current_user,opt_password,
+ opt_silent))
+ {
+ if (connected)
+ mysql_close(&mysql);
+ glob_buffer.free();
+ old_buffer.free();
+ batch_readline_end(status.line_buff);
+ my_end(0);
+ exit(1);
+ }
+ if (!status.batch)
+ ignore_errors=1; // Don't abort monitor
+ signal(SIGINT, mysql_end); // Catch SIGINT to clean up
+
+ /*
+ ** Run in interactive mode like the ingres/postgres monitor
+ */
+
+ put_info("Welcome to the MySQL monitor. Commands end with ; or \\g.",
+ INFO_INFO);
+ sprintf((char*) glob_buffer.ptr(),
+ "Your MySQL connection id is %ld to server version: %s\n",
+ mysql_thread_id(&mysql),mysql_get_server_info(&mysql));
+ put_info((char*) glob_buffer.ptr(),INFO_INFO);
+
+#ifdef HAVE_READLINE
+ initialize_readline(my_progname);
+ if (!status.batch && !quick && !opt_html)
+ {
+ /*read-history from file, default ~/.mysql_history*/
+ if (getenv("MYSQL_HISTFILE"))
+ histfile=my_strdup(getenv("MYSQL_HISTFILE"),MYF(MY_WME));
+ else if (getenv("HOME"))
+ {
+ histfile=(char*) my_malloc(strlen(getenv("HOME"))
+ + strlen("/.mysql_history")+2,
+ MYF(MY_WME));
+ if (histfile)
+ sprintf(histfile,"%s/.mysql_history",getenv("HOME"));
+ }
+ if (histfile)
+ {
+ if (verbose)
+ printf("Reading history-file %s\n",histfile);
+ read_history(histfile);
+ }
+ }
+#endif
+ sprintf(buff, "Type '%s' for help.\n", no_named_cmds ? "\\h" : "help");
+ put_info(buff,INFO_INFO);
+ status.exit_status=read_lines(1); // read lines and execute them
+ mysql_end(0);
+#ifndef _lint
+ DBUG_RETURN(0); // Keep compiler happy
+#endif
+}
+
+sig_handler mysql_end(int sig)
+{
+ if (connected)
+ mysql_close(&mysql);
+#ifdef HAVE_READLINE
+ if (!status.batch && !quick && ! opt_html)
+ {
+ /* write-history */
+ if (verbose)
+ printf("Writing history-file %s\n",histfile);
+ write_history(histfile);
+ }
+ batch_readline_end(status.line_buff);
+ completion_hash_free(&ht);
+#endif
+ put_info(sig ? "Aborted" : "Bye", INFO_RESULT);
+ glob_buffer.free();
+ old_buffer.free();
+ my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(histfile,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
+ my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
+ exit(status.exit_status);
+}
+
+enum options {OPT_CHARSETS_DIR=256, OPT_DEFAULT_CHARSET} ;
+
+
+static struct option long_options[] =
+{
+ {"i-am-a-dummy", no_argument, 0, 'U'},
+ {"batch", no_argument, 0, 'B'},
+ {"character-sets-dir",required_argument,0, OPT_CHARSETS_DIR},
+ {"compress", no_argument, 0, 'C'},
+#ifndef DBUG_OFF
+ {"debug", optional_argument, 0, '#'},
+#endif
+ {"database", required_argument, 0, 'D'},
+ {"debug-info", no_argument, 0, 'T'},
+ {"default-character-set", required_argument, 0, OPT_DEFAULT_CHARSET},
+ {"execute", required_argument, 0, 'e'},
+ {"force", no_argument, 0, 'f'},
+ {"help", no_argument, 0, '?'},
+ {"html", no_argument, 0, 'H'},
+ {"host", required_argument, 0, 'h'},
+ {"ignore-spaces", no_argument, 0, 'i'},
+ {"no-auto-rehash",no_argument, 0, 'A'},
+ {"no-named-commands", no_argument, 0, 'g'},
+ {"one-database", no_argument, 0, 'o'},
+ {"password", optional_argument, 0, 'p'},
+#ifdef __WIN__
+ {"pipe", no_argument, 0, 'W'},
+#endif
+ {"port", required_argument, 0, 'P'},
+ {"quick", no_argument, 0, 'q'},
+ {"set-variable", required_argument, 0, 'O'},
+ {"raw", no_argument, 0, 'r'},
+ {"safe-updates", no_argument, 0, 'U'},
+ {"silent", no_argument, 0, 's'},
+ {"skip-column-names",no_argument, 0, 'N'},
+ {"skip-line-numbers",no_argument, 0, 'L'},
+ {"socket", required_argument, 0, 'S'},
+#include "sslopt-longopts.h"
+ {"table", no_argument, 0, 't'},
+#ifndef DONT_ALLOW_USER_CHANGE
+ {"user", required_argument, 0, 'u'},
+#endif
+ {"unbuffered", no_argument, 0, 'n'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"vertical", no_argument, 0, 'E'},
+ {"wait", no_argument, 0, 'w'},
+ {0, 0, 0, 0}
+};
+
+
+CHANGEABLE_VAR changeable_vars[] = {
+ { "max_allowed_packet", (long*) &max_allowed_packet,24*1024L*1024L,4096,
+ 24*1024L*1024L, MALLOC_OVERHEAD,1024},
+ { "net_buffer_length",(long*) &net_buffer_length,16384,1024,24*1024*1024L,
+ MALLOC_OVERHEAD,1024},
+ { "select_limit", (long*) &select_limit, 1000L, 1, ~0L, 0, 1},
+ { "max_join_size", (long*) &max_join_size, 1000000L, 1, ~0L, 0, 1},
+ { 0, 0, 0, 0, 0, 0, 0}
+};
+
+
+static void usage(int version)
+{
+ printf("%s Ver 10.8 Distrib %s, for %s (%s)\n",
+ my_progname, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
+ if (version)
+ return;
+ puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB");
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
+ printf("Usage: %s [OPTIONS] [database]\n", my_progname);
+ printf("\n\
+ -?, --help Display this help and exit\n\
+ -A, --no-auto-rehash No automatic rehashing. One has to use 'rehash' to\n\
+ get table and field completion. This gives a quicker\n\
+ start of mysql and disables rehashing on reconnect.\n\
+ -B, --batch Print results with a tab as separator, each row on\n\
+ a new line. Doesn't use history file\n\
+ --character-sets-dir=...\n\
+ Directory where character sets are\n\
+ -C, --compress Use compression in server/client protocol\n");
+#ifndef DBUG_OFF
+ printf("\
+ -#, --debug[=...] Debug log. Default is '%s'\n",default_dbug_option);
+#endif
+ printf("\
+ -D, --database=.. Database to use\n\
+ --default-character-set=...\n\
+ Set the default character set\n\
+ -e, --execute=... Execute command and quit.(Output like with --batch)\n\
+ -E, --vertical Print the output of a query (rows) vertically\n\
+ -f, --force Continue even if we get an sql error.\n\
+ -g, --no-named-commands\n\
+ Named commands are disabled. Use \\* form only\n\
+ -i, --ignore-space Ignore space after function names\n\
+ -h, --host=... Connect to host\n\
+ -H, --html Produce HTML output\n\
+ -L, --skip-line-numbers Don't write line number for errors\n\
+ -n, --unbuffered Flush buffer after each query\n\
+ -N, --skip-column-names Don't write column names in results\n\
+ -O, --set-variable var=option\n\
+ Give a variable an value. --help lists variables\n\
+ -o, --one-database Only update the default database. This is useful\n\
+ for skipping updates to other database in the update\n\
+ log.\n\
+ -p[password], --password[=...]\n\
+ Password to use when connecting to server\n\
+ If password is not given it's asked from the tty.\n");
+#ifdef __WIN__
+ puts(" -W, --pipe Use named pipes to connect to server");
+#endif
+ printf("\n\
+ -P --port=... Port number to use for connection\n\
+ -q, --quick Don't cache result, print it row by row. This may\n\
+ slow down the server if the output is suspended.\n\
+ Doesn't use history file\n\
+ -r, --raw Write fields without conversion. Used with --batch\n\
+ -s, --silent Be more silent.\n\
+ -S --socket=... Socket file to use for connection\n");
+#include "sslopt-usage.h"
+ printf("\
+ -t --table Output in table format\n\
+ -T, --debug-info Print some debug info at exit\n");
+#ifndef DONT_ALLOW_USER_CHANGE
+ printf("\
+ -u, --user=# User for login if not current user\n");
+#endif
+ printf("\
+ -U, --safe-updates[=#], --i-am-a-dummy[=#]\n\
+ Only allow UPDATE and DELETE that uses keys\n\
+ -v, --verbose Write more (-v -v -v gives the table output format)\n\
+ -V, --version Output version information and exit\n\
+ -w, --wait Wait and retry if connection is down\n");
+ print_defaults("my",load_default_groups);
+
+ printf("\nPossible variables for option --set-variable (-O) are:\n");
+ for (uint i=0 ; changeable_vars[i].name ; i++)
+ printf("%-20s current value: %lu\n",
+ changeable_vars[i].name,
+ (ulong) *changeable_vars[i].varptr);
+}
+
+
+static int get_options(int argc, char **argv)
+{
+ int c,option_index=0;
+ bool tty_password=0;
+
+ set_all_changeable_vars(changeable_vars);
+ while ((c=getopt_long(argc,argv,"?ABCD:LfgHinNoqrstTUvVwWEe:h:O:P:S:u:#::p::",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case OPT_DEFAULT_CHARSET:
+ default_charset= optarg;
+ break;
+ case OPT_CHARSETS_DIR:
+ charsets_dir= optarg;
+ break;
+ case 'D':
+ my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
+ current_db=my_strdup(optarg,MYF(MY_WME));
+ break;
+ case 'e':
+ status.batch=1;
+ status.add_to_history=0;
+ batch_readline_end(status.line_buff); // If multiple -e
+ if (!(status.line_buff=batch_readline_command(optarg)))
+ return 1;
+ ignore_errors=0;
+ break;
+ case 'f':
+ ignore_errors=1;
+ break;
+ case 'h':
+ my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
+ current_host=my_strdup(optarg,MYF(MY_WME));
+ break;
+#ifndef DONT_ALLOW_USER_CHANGE
+ case 'u':
+ my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
+ current_user= my_strdup(optarg,MYF(MY_WME));
+ break;
+#endif
+ case 'U':
+ if (!optarg)
+ safe_updates=1;
+ else
+ safe_updates=atoi(optarg) != 0;
+ break;
+ case 'o':
+ one_database=skip_updates=1;
+ break;
+ case 'O':
+ if (set_changeable_var(optarg, changeable_vars))
+ {
+ usage(0);
+ return(1);
+ }
+ break;
+ case 'p':
+ if (optarg)
+ {
+ my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
+ opt_password=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; // Destroy argument
+ }
+ else
+ tty_password=1;
+ break;
+ case 't':
+ output_tables=1;
+ break;
+ case 'r':
+ opt_raw_data=1;
+ break;
+ case '#':
+ DBUG_PUSH(optarg ? optarg : default_dbug_option);
+ info_flag=1;
+ break;
+ case 'q': quick=1; break;
+ case 's': opt_silent++; break;
+ case 'T': info_flag=1; break;
+ case 'n': unbuffered=1; break;
+ case 'v': verbose++; break;
+ case 'E': vertical=1; break;
+ case 'w': wait_flag=1; break;
+ case 'A': no_rehash=1; break;
+ case 'g': no_named_cmds=1; break;
+ case 'H': opt_html=1; break;
+ case 'i': connect_flag|= CLIENT_IGNORE_SPACE; break;
+ case 'B':
+ if (!status.batch)
+ {
+ status.batch=1;
+ status.add_to_history=0;
+ opt_silent++; // more silent
+ }
+ break;
+ case 'C':
+ opt_compress=1;
+ break;
+ case 'L':
+ skip_line_numbers=1;
+ break;
+ case 'N':
+ skip_column_names=1;
+ break;
+ case 'P':
+ opt_mysql_port= (unsigned int) atoi(optarg);
+ break;
+ case 'S':
+ my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR));
+ opt_mysql_unix_port= my_strdup(optarg,MYF(0));
+ break;
+ case 'W':
+#ifdef __WIN__
+ opt_mysql_unix_port=MYSQL_NAMEDPIPE;
+#endif
+ break;
+ case 'V': usage(1); exit(0);
+ case 'I':
+ case '?':
+ usage(0);
+ exit(0);
+#include "sslopt-case.h"
+ default:
+ fprintf(stderr,"illegal option: -%c\n",opterr);
+ usage(0);
+ exit(1);
+ }
+ }
+ if (default_charset)
+ {
+ if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
+ exit(1);
+ }
+ argc-=optind;
+ argv+=optind;
+ if (argc > 1)
+ {
+ usage(0);
+ exit(1);
+ }
+ if (argc == 1)
+ {
+ my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
+ current_db= my_strdup(*argv,MYF(MY_WME));
+ }
+ if (!current_host)
+ { /* If we don't have a hostname have a look at MYSQL_HOST */
+ char *tmp=(char *) getenv("MYSQL_HOST");
+ if (tmp)
+ current_host = my_strdup(tmp,MYF(MY_WME));
+ }
+ if (tty_password)
+ opt_password=get_tty_password(NullS);
+ return(0);
+}
+
+
+static int read_lines(bool execute_commands)
+{
+#ifdef __WIN__
+ char linebuffer[254];
+#endif
+ char *line;
+ char in_string=0;
+ ulong line_number=0;
+ COMMANDS *com;
+ status.exit_status=1;
+
+ for (;;)
+ {
+ if (status.batch || !execute_commands)
+ {
+ line=batch_readline(status.line_buff);
+ line_number++;
+ if (!glob_buffer.length())
+ status.query_start_line=line_number;
+ }
+ else
+#ifdef __WIN__
+ {
+ printf(glob_buffer.is_empty() ? "mysql> " :
+ !in_string ? " -> " :
+ in_string == '\'' ?
+ " '> " : " \"> ");
+ linebuffer[0]=(char) sizeof(linebuffer);
+ line=_cgets(linebuffer);
+ }
+#else
+ line=readline((char*) (glob_buffer.is_empty() ? "mysql> " :
+ !in_string ? " -> " :
+ in_string == '\'' ?
+ " '> " : " \"> "));
+#endif
+ if (!line) // End of file
+ {
+ status.exit_status=0;
+ break;
+ }
+ if (!in_string && (line[0] == '#' ||
+ (line[0] == '-' && line[1] == '-') ||
+ line[0] == 0))
+ continue; // Skipp comment lines
+
+ /* Check if line is a mysql command line */
+ /* (We want to allow help, print and clear anywhere at line start */
+ if (execute_commands && !no_named_cmds && !in_string &&
+ (com=find_command(line,0)))
+ {
+ if ((*com->func)(&glob_buffer,line) > 0)
+ break;
+ if (glob_buffer.is_empty()) // If buffer was emptied
+ in_string=0;
+#ifdef HAVE_READLINE
+ if (status.add_to_history)
+ add_history(line);
+#endif
+ continue;
+ }
+ if (add_line(glob_buffer,line,&in_string))
+ break;
+ }
+ /* if in batch mode, send last query even if it doesn't end with \g or go */
+
+ if ((status.batch || !execute_commands) && !status.exit_status)
+ {
+ remove_cntrl(glob_buffer);
+ if (!glob_buffer.is_empty())
+ {
+ status.exit_status=1;
+ if (com_go(&glob_buffer,line) <= 0)
+ status.exit_status=0;
+ }
+ }
+ return status.exit_status;
+}
+
+
+static COMMANDS *find_command (char *name,char cmd_char)
+{
+ uint len;
+ char *end;
+
+ if (!name)
+ {
+ len=0;
+ end=0;
+ }
+ else
+ {
+ while (isspace(*name))
+ name++;
+ if (strchr(name,';') || strstr(name,"\\g"))
+ return ((COMMANDS *) 0);
+ if ((end=strcont(name," \t")))
+ {
+ len=(uint) (end - name);
+ while (isspace(*end))
+ end++;
+ if (!*end)
+ end=0; // no arguments to function
+ }
+ else
+ len=strlen(name);
+ }
+
+ for (uint i= 0; commands[i].name; i++)
+ {
+ if (commands[i].func &&
+ ((name && !my_casecmp(name,commands[i].name,len) &&
+ !commands[i].name[len] &&
+ (!end || (end && commands[i].takes_params))) ||
+ !name && commands[i].cmd_char == cmd_char))
+ return (&commands[i]);
+ }
+ return ((COMMANDS *) 0);
+}
+
+
+static bool add_line(String &buffer,char *line,char *in_string)
+{
+ uchar inchar;
+ char buff[80],*pos,*out;
+ COMMANDS *com;
+
+ if (!line[0] && buffer.is_empty())
+ return 0;
+#ifdef HAVE_READLINE
+ if (status.add_to_history && line[0])
+ add_history(line);
+#endif
+#ifdef USE_MB
+ char *strend=line+strlen(line);
+#endif
+
+ for (pos=out=line ; (inchar= (uchar) *pos) ; pos++)
+ {
+ if (isspace(inchar) && out == line && buffer.is_empty())
+ continue;
+#ifdef USE_MB
+ int l;
+/* if ((l = ismbchar(pos, pos+MBMAXLEN))) { Wei He: I think it's wrong! */
+ if (use_mb(default_charset_info) &&
+ (l = my_ismbchar(default_charset_info, pos, strend))) {
+ while (l--)
+ *out++ = *pos++;
+ pos--;
+ continue;
+ }
+#endif
+ if (inchar == '\\')
+ { // mSQL or postgreSQL style command ?
+ if (!(inchar = (uchar) *++pos))
+ break; // readline adds one '\'
+ if (*in_string || inchar == 'N')
+ { // Don't allow commands in string
+ *out++='\\';
+ *out++= (char) inchar;
+ continue;
+ }
+ if ((com=find_command(NullS,(char) inchar)))
+ {
+ const String tmp(line,(uint) (out-line));
+ buffer.append(tmp);
+ if ((*com->func)(&buffer,pos-1) > 0)
+ return 1; // Quit
+ if (com->takes_params)
+ {
+ for (pos++ ; *pos && *pos != ';' ; pos++) ; // Remove parameters
+ if (!*pos)
+ pos--;
+ }
+ out=line;
+ }
+ else
+ {
+ sprintf(buff,"Unknown command '\\%c'.",inchar);
+ if (put_info(buff,INFO_ERROR) > 0)
+ return 1;
+ *out++='\\';
+ *out++=(char) inchar;
+ continue;
+ }
+ }
+ else if (inchar == ';' && !*in_string)
+ { // ';' is end of command
+ if (out != line)
+ buffer.append(line,(uint) (out-line)); // Add this line
+ if ((com=find_command(buffer.c_ptr(),0)))
+ {
+ if ((*com->func)(&buffer,buffer.c_ptr()) > 0)
+ return 1; // Quit
+ }
+ else
+ {
+ int error=com_go(&buffer,0);
+ if (error)
+ {
+ return error < 0 ? 0 : 1; // < 0 is not fatal
+ }
+ }
+ buffer.length(0);
+ out=line;
+ }
+ else if (!*in_string && (inchar == '#' ||
+ inchar == '-' && pos[1] == '-' &&
+ isspace(pos[2])))
+ break; // comment to end of line
+ else
+ { // Add found char to buffer
+ if (inchar == *in_string)
+ *in_string=0;
+ else if (!*in_string && (inchar == '\'' || inchar == '"'))
+ *in_string=(char) inchar;
+ *out++ = (char) inchar;
+ }
+ }
+ if (out != line || !buffer.is_empty())
+ {
+ *out++='\n';
+ uint length=(uint) (out-line);
+ if (buffer.length() + length >= buffer.alloced_length())
+ buffer.realloc(buffer.length()+length+IO_SIZE);
+ if (buffer.append(line,length))
+ return 1;
+ }
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Interface to Readline Completion */
+/* */
+/* **************************************************************** */
+
+#ifdef HAVE_READLINE
+
+static char *new_command_generator(char *text, int);
+static char **new_mysql_completion (char *text, int start, int end);
+
+/* Tell the GNU Readline library how to complete. We want to try to complete
+ on command names if this is the first word in the line, or on filenames
+ if not. */
+
+char **no_completion (char *text __attribute__ ((unused)),
+ char *word __attribute__ ((unused)))
+{
+ return 0; /* No filename completion */
+}
+
+static void initialize_readline (char *name)
+{
+ /* Allow conditional parsing of the ~/.inputrc file. */
+ rl_readline_name = name;
+
+ /* Tell the completer that we want a crack first. */
+ /* rl_attempted_completion_function = (CPPFunction *)mysql_completion;*/
+ rl_attempted_completion_function = (CPPFunction *) new_mysql_completion;
+ rl_completion_entry_function=(Function *) no_completion;
+}
+
+/* Attempt to complete on the contents of TEXT. START and END show the
+ region of TEXT that contains the word to complete. We can use the
+ entire line in case we want to do some simple parsing. Return the
+ array of matches, or NULL if there aren't any. */
+
+
+static char **new_mysql_completion (char *text,
+ int start __attribute__((unused)),
+ int end __attribute__((unused)))
+{
+ if (!status.batch && !quick)
+ return completion_matches(text, (CPFunction*) new_command_generator);
+ else
+ return (char**) 0;
+}
+
+static char *new_command_generator(char *text,int state)
+{
+ static int textlen;
+ char *ptr;
+ static Bucket *b;
+ static entry *e;
+ static uint i;
+
+ if (!state) {
+ textlen=strlen(text);
+ }
+
+ if (textlen>0) { /* lookup in the hash */
+ if (!state) {
+ uint len;
+
+ b = find_all_matches(&ht,text,strlen(text),&len);
+ if (!b) {
+ return NullS;
+ }
+ e = b->pData;
+ }
+
+ while (e) {
+ ptr= strdup(e->str);
+ e = e->pNext;
+ return ptr;
+ }
+ } else { /* traverse the entire hash, ugly but works */
+
+ if (!state) {
+ i=0;
+ /* find the first used bucket */
+ while (i<ht.nTableSize) {
+ if (ht.arBuckets[i]) {
+ b = ht.arBuckets[i];
+ e = b->pData;
+ break;
+ }
+ i++;
+ }
+ }
+ ptr= NullS;
+ while (e && !ptr) { /* find valid entry in bucket */
+ if (strlen(e->str)==b->nKeyLength) {
+ ptr = strdup(e->str);
+ }
+ /* find the next used entry */
+ e = e->pNext;
+ if (!e) { /* find the next used bucket */
+ b = b->pNext;
+ if (!b) {
+ i++;
+ while (i<ht.nTableSize) {
+ if (ht.arBuckets[i]) {
+ b = ht.arBuckets[i];
+ e = b->pData;
+ break;
+ }
+ i++;
+ }
+ } else {
+ e = b->pData;
+ }
+ }
+ }
+ if (ptr) {
+ return ptr;
+ }
+ }
+ return NullS;
+}
+
+
+/* Build up the completion hash */
+
+static void build_completion_hash(bool skip_rehash,bool write_info)
+{
+ COMMANDS *cmd=commands;
+ static MYSQL_RES *databases=0,*tables=0,*fields;
+ static char ***field_names= 0;
+ MYSQL_ROW database_row,table_row;
+ MYSQL_FIELD *sql_field;
+ char buf[NAME_LEN*2+2]; // table name plus field name plus 2
+ int i,j,num_fields;
+ DBUG_ENTER("build_completion_hash");
+
+ if (status.batch || quick)
+ DBUG_VOID_RETURN; // We don't need completion in batches
+
+ completion_hash_clean(&ht);
+ if (tables)
+ {
+ mysql_free_result(tables);
+ tables=0;
+ }
+ if (databases) {
+ mysql_free_result(databases);
+ databases=0;
+ }
+
+ /* hash SQL commands */
+ while (cmd->name) {
+ add_word(&ht,(char*) cmd->name);
+ cmd++;
+ }
+ if (skip_rehash)
+ DBUG_VOID_RETURN;
+
+ /* hash MySQL functions (to be implemented) */
+
+ /* hash all database names */
+ if (mysql_query(&mysql,"show databases")==0) {
+ if (!(databases = mysql_store_result(&mysql)))
+ put_info(mysql_error(&mysql),INFO_INFO);
+ else
+ {
+ while ((database_row=mysql_fetch_row(databases)))
+ add_word(&ht,(char*) database_row[0]);
+ }
+ }
+ /* hash all table names */
+ if (mysql_query(&mysql,"show tables")==0)
+ {
+ if (!(tables = mysql_store_result(&mysql)))
+ put_info(mysql_error(&mysql),INFO_INFO);
+ else
+ {
+ if (mysql_num_rows(tables) > 0 && !opt_silent && write_info)
+ {
+ printf("\
+Reading table information for completion of table and column names\n\
+You can turn off this feature to get a quicker startup with -A\n\n");
+ }
+ while ((table_row=mysql_fetch_row(tables)))
+ {
+ if (!completion_hash_exists(&ht,(char*) table_row[0],
+ strlen((const char*) table_row[0])))
+ add_word(&ht,table_row[0]);
+ }
+ }
+ }
+ if (field_names) {
+ for (i=0; field_names[i]; i++) {
+ for (j=0; field_names[i][j]; j++) {
+ my_free(field_names[i][j],MYF(0));
+ }
+ my_free((gptr) field_names[i],MYF(0));
+ }
+ my_free((gptr) field_names,MYF(0));
+ }
+ field_names=0;
+
+ /* hash all field names, both with the table prefix and without it */
+ if (!tables) { /* no tables */
+ DBUG_VOID_RETURN;
+ }
+ mysql_data_seek(tables,0);
+ field_names = (char ***) my_malloc(sizeof(char **) *
+ (uint) (mysql_num_rows(tables)+1),
+ MYF(MY_WME));
+ if (!field_names)
+ DBUG_VOID_RETURN;
+ field_names[mysql_num_rows(tables)]='\0';
+ i=0;
+ while ((table_row=mysql_fetch_row(tables)))
+ {
+ if ((fields=mysql_list_fields(&mysql,(const char*) table_row[0],NullS)))
+ {
+ num_fields=mysql_num_fields(fields);
+ field_names[i] = (char **) my_malloc(sizeof(char *)*(num_fields*2+1),
+ MYF(0));
+ if (!field_names[i])
+ {
+ continue;
+ }
+ field_names[i][num_fields*2]='\0';
+ j=0;
+ while ((sql_field=mysql_fetch_field(fields)))
+ {
+ sprintf(buf,"%s.%s",table_row[0],sql_field->name);
+ field_names[i][j] = my_strdup(buf,MYF(0));
+ add_word(&ht,field_names[i][j]);
+ field_names[i][num_fields+j] = my_strdup(sql_field->name,MYF(0));
+ if (!completion_hash_exists(&ht,field_names[i][num_fields+j],
+ strlen(field_names[i][num_fields+j])))
+ add_word(&ht,field_names[i][num_fields+j]);
+ j++;
+ }
+ }
+ else
+ printf("Didn't find any fields in table '%s'\n",table_row[0]);
+ i++;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+ /* for gnu readline */
+
+#ifndef HAVE_INDEX
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern char *index(const char *,pchar c),*rindex(const char *,pchar);
+
+char *index(const char *s,pchar c)
+{
+ for (;;)
+ {
+ if (*s == (char) c) return (char*) s;
+ if (!*s++) return NullS;
+ }
+}
+
+char *rindex(const char *s,pchar c)
+{
+ reg3 char *t;
+
+ t = NullS;
+ do if (*s == (char) c) t = (char*) s; while (*s++);
+ return (char*) t;
+}
+#ifdef __cplusplus
+}
+#endif
+#endif
+#endif /* HAVE_READLINE */
+
+static int reconnect(void)
+{
+ if (!status.batch)
+ {
+ put_info("No connection. Trying to reconnect...",INFO_INFO);
+ (void) com_connect((String *) 0, 0);
+ if(!no_rehash) com_rehash(NULL, NULL);
+ }
+ if (!connected)
+ return put_info("Can't connect to the server\n",INFO_ERROR);
+ return 0;
+}
+
+
+/***************************************************************************
+ The different commands
+***************************************************************************/
+
+static int
+com_help (String *buffer __attribute__((unused)),
+ char *line __attribute__((unused)))
+{
+ reg1 int i;
+
+ put_info("\nMySQL commands:",INFO_INFO);
+ for (i = 0; commands[i].name; i++)
+ {
+ if (commands[i].func)
+ printf("%s\t(\\%c)\t%s\n", commands[i].name,commands[i].cmd_char,
+ commands[i].doc);
+ }
+ if (connected)
+ printf("\nConnection id: %ld (Can be used with mysqladmin kill)\n\n",
+ mysql_thread_id(&mysql));
+ else
+ printf("Not connected! Reconnect with 'connect'!\n\n");
+ return 0;
+}
+
+
+ /* ARGSUSED */
+static int
+com_clear(String *buffer,char *line __attribute__((unused)))
+{
+ buffer->length(0);
+ return 0;
+}
+
+
+/*
+** Execute command
+** Returns: 0 if ok
+** -1 if not fatal error
+** 1 if fatal error
+*/
+
+
+static int
+com_go(String *buffer,char *line __attribute__((unused)))
+{
+ char buff[160],time_buff[32];
+ MYSQL_RES *result;
+ ulong timer;
+ uint error=0;
+
+ if (!status.batch)
+ {
+ old_buffer= *buffer; // Save for edit command
+ old_buffer.copy();
+ }
+
+ /* Remove garbage for nicer messages */
+ LINT_INIT(buff[0]);
+ remove_cntrl(*buffer);
+
+ if (buffer->is_empty())
+ {
+ if (status.batch) // Ignore empty quries
+ return 0;
+ return put_info("No query specified\n",INFO_ERROR);
+
+ }
+ if (!connected && reconnect())
+ {
+ buffer->length(0); // Remove query on error
+ return status.batch ? 1 : -1; // Fatal error
+ }
+ if (verbose)
+ (void) com_print(buffer,0);
+
+ if (skip_updates &&
+ (buffer->length() < 4 || my_sortcmp(buffer->ptr(),"SET ",4)))
+ {
+ (void) put_info("Ignoring query to other database",INFO_INFO);
+ return 0;
+ }
+
+ timer=start_timer();
+ for (uint retry=0;; retry++)
+ {
+ if (!mysql_real_query(&mysql,buffer->ptr(),buffer->length()))
+ break;
+ error=put_info(mysql_error(&mysql),INFO_ERROR, mysql_errno(&mysql));
+ if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 || status.batch)
+ {
+ buffer->length(0); // Remove query on error
+ return error;
+ }
+ if (reconnect())
+ {
+ buffer->length(0); // Remove query on error
+ return error;
+ }
+ }
+ error=0;
+ buffer->length(0);
+
+ if (quick)
+ {
+ if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql))
+ {
+ return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
+ }
+ }
+ else
+ {
+ if (!(result=mysql_store_result(&mysql)))
+ {
+ if (mysql_error(&mysql)[0])
+ {
+ return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
+ }
+ }
+ }
+
+ if (verbose >= 3 || !opt_silent)
+ mysql_end_timer(timer,time_buff);
+ else
+ time_buff[0]=0;
+ if (result)
+ {
+ if (!mysql_num_rows(result) && ! quick)
+ {
+ sprintf(buff,"Empty set%s",time_buff);
+ }
+ else
+ {
+ if (opt_html)
+ print_table_data_html(result);
+ else if (vertical)
+ print_table_data_vertically(result);
+ else if (opt_silent && verbose <= 2 && !output_tables)
+ print_tab_data(result);
+ else
+ print_table_data(result);
+ sprintf(buff,"%ld %s in set%s",
+ (long) mysql_num_rows(result),
+ (long) mysql_num_rows(result) == 1 ? "row" : "rows",
+ time_buff);
+ }
+ }
+ else if (mysql_affected_rows(&mysql) == ~(ulonglong) 0)
+ sprintf(buff,"Query OK%s",time_buff);
+ else
+ sprintf(buff,"Query OK, %ld %s affected%s",
+ (long) mysql_affected_rows(&mysql),
+ (long) mysql_affected_rows(&mysql) == 1 ? "row" : "rows",
+ time_buff);
+ put_info(buff,INFO_RESULT);
+ if (mysql_info(&mysql))
+ put_info(mysql_info(&mysql),INFO_RESULT);
+ put_info("",INFO_RESULT); // Empty row
+
+ if (result && !mysql_eof(result)) /* Something wrong when using quick */
+ error=put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
+ else if (unbuffered)
+ fflush(stdout);
+ mysql_free_result(result);
+ return error; /* New command follows */
+}
+
+static int
+com_ego(String *buffer,char *line)
+{
+ int result;
+ bool oldvertical=vertical;
+ vertical=1;
+ result=com_go(buffer,line);
+ vertical=oldvertical;
+ return result;
+}
+
+
+static void
+print_table_data(MYSQL_RES *result)
+{
+ String separator(256);
+ MYSQL_ROW cur;
+ MYSQL_FIELD *field;
+ bool *num_flag;
+
+ num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result));
+ separator.copy("+",1);
+ while ((field = mysql_fetch_field(result)))
+ {
+ uint length=skip_column_names ? 0 : strlen(field->name);
+ if (quick)
+ length=max(length,field->length);
+ else
+ length=max(length,field->max_length);
+ if (length < 4 && !IS_NOT_NULL(field->flags))
+ length=4; // Room for "NULL"
+ field->max_length=length+1;
+ separator.fill(separator.length()+length+2,'-');
+ separator.append('+');
+ }
+ puts(separator.c_ptr());
+
+ if (!skip_column_names)
+ {
+ mysql_field_seek(result,0);
+ (void) fputs("|",stdout);
+ for (uint off=0; (field = mysql_fetch_field(result)) ; off++)
+ {
+ printf(" %-*s|",field->max_length,field->name);
+ num_flag[off]= IS_NUM(field->type);
+ }
+ (void) fputc('\n',stdout);
+ puts(separator.c_ptr());
+ }
+
+ while ((cur = mysql_fetch_row(result)))
+ {
+ (void) fputs("|",stdout);
+ mysql_field_seek(result,0);
+ for (uint off=0 ; off < mysql_num_fields(result); off++)
+ {
+ field = mysql_fetch_field(result);
+ uint length=field->max_length;
+ printf(num_flag[off] ? "%*s |" : " %-*s|",
+ length,cur[off] ? (char*) cur[off] : "NULL");
+ }
+ (void) fputc('\n',stdout);
+ }
+ puts(separator.c_ptr());
+ my_afree((gptr) num_flag);
+}
+
+static void
+print_table_data_html(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ MYSQL_FIELD *field;
+
+ mysql_field_seek(result,0);
+ printf("<TABLE BORDER=1>\n");
+ printf("<TR>\n");
+ if (!skip_column_names)
+ {
+ while((field = mysql_fetch_field(result)))
+ {
+ printf("<TH>%s</TH>",field->name ? (field->name[0] ? field->name:" &nbsp; "):"NULL");
+ }
+ puts("\n</TR>");
+ }
+ while ((cur = mysql_fetch_row(result)))
+ {
+ puts("<TR>");
+ for (uint i=0; i < mysql_num_fields(result); i++)
+ {
+ ulong *lengths=mysql_fetch_lengths(result);
+ fputs("<TD>",stdout);
+ safe_put_field(cur[i],lengths[i]);
+ fputs("</TD>",stdout);
+ }
+ puts("\n</TR>");
+ }
+ puts("</TABLE>");
+}
+
+
+
+static void
+print_table_data_vertically(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ uint max_length=0;
+ MYSQL_FIELD *field;
+
+ while ((field = mysql_fetch_field(result)))
+ {
+ uint length=strlen(field->name);
+ if (length > max_length)
+ max_length= length;
+ field->max_length=length;
+ }
+
+ mysql_field_seek(result,0);
+ for (uint row_count=1; (cur= mysql_fetch_row(result)); row_count++)
+ {
+ mysql_field_seek(result,0);
+ printf("*************************** %d. row ***************************\n",
+ row_count);
+ for (uint off=0; off < mysql_num_fields(result); off++)
+ {
+ field= mysql_fetch_field(result);
+ printf("%*s: ",(int) max_length,field->name);
+ printf("%s\n",cur[off] ? (char*) cur[off] : "NULL");
+ }
+ }
+}
+
+
+static void
+safe_put_field(const char *pos,ulong length)
+{
+ if (!pos)
+ fputs("NULL",stdout);
+ else
+ {
+ if (opt_raw_data)
+ fputs(pos,stdout);
+ else for (const char *end=pos+length ; pos != end ; pos++)
+ {
+#ifdef USE_MB
+ int l;
+ if (use_mb(default_charset_info) &&
+ (l = my_ismbchar(default_charset_info, pos, end))) {
+ while (l--)
+ putchar(*pos++);
+ pos--;
+ continue;
+ }
+#endif
+ if (!*pos)
+ fputs("\\0",stdout); // This makes everything hard
+ else if (*pos == '\t')
+ fputs("\\t",stdout); // This would destroy tab format
+ else if (*pos == '\n')
+ fputs("\\n",stdout); // This too
+ else if (*pos == '\\')
+ fputs("\\\\",stdout);
+ else
+ putchar(*pos);
+ }
+ }
+}
+
+
+static void
+print_tab_data(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ MYSQL_FIELD *field;
+ ulong *lengths;
+
+ if (opt_silent < 2 && !skip_column_names)
+ {
+ int first=0;
+ while ((field = mysql_fetch_field(result)))
+ {
+ if (first++)
+ (void) fputc('\t',stdout);
+ (void) fputs(field->name,stdout);
+ }
+ (void) fputc('\n',stdout);
+ }
+ while ((cur = mysql_fetch_row(result)))
+ {
+ lengths=mysql_fetch_lengths(result);
+ safe_put_field(cur[0],lengths[0]);
+ for (uint off=1 ; off < mysql_num_fields(result); off++)
+ {
+ (void) fputc('\t',stdout);
+ safe_put_field(cur[off],lengths[off]);
+ }
+ (void) fputc('\n',stdout);
+ }
+}
+
+
+static int
+com_edit(String *buffer,char *line __attribute__((unused)))
+{
+#ifdef __WIN__
+ put_info("Sorry, you can't send the result to an editor in Win32",
+ INFO_ERROR);
+#else
+ char *filename,buff[160];
+ int fd,tmp;
+ const char *editor;
+
+ filename = my_tempnam(NullS,"sql",MYF(MY_WME));
+ if ((fd = my_create(filename,0,O_CREAT | O_WRONLY, MYF(MY_WME))) < 0)
+ goto err;
+ if (buffer->is_empty() && !old_buffer.is_empty())
+ (void) my_write(fd,(byte*) old_buffer.ptr(),old_buffer.length(),
+ MYF(MY_WME));
+ else
+ (void) my_write(fd,(byte*) buffer->ptr(),buffer->length(),MYF(MY_WME));
+ (void) my_close(fd,MYF(0));
+
+ if (!(editor = (char *)getenv("EDITOR")) &&
+ !(editor = (char *)getenv("VISUAL")))
+ editor = "vi";
+ strxmov(buff,editor," ",filename,NullS);
+ (void) system(buff);
+
+ MY_STAT stat_arg;
+ if (!my_stat(filename,&stat_arg,MYF(MY_WME)))
+ goto err;
+ if ((fd = my_open(filename,O_RDONLY, MYF(MY_WME))) < 0)
+ goto err;
+ (void) buffer->alloc((uint) stat_arg.st_size);
+ if ((tmp=read(fd,(char*) buffer->ptr(),buffer->alloced_length())) >= 0L)
+ buffer->length((uint) tmp);
+ else
+ buffer->length(0);
+ (void) my_close(fd,MYF(0));
+ (void) my_delete(filename,MYF(MY_WME));
+err:
+ free(filename);
+#endif
+ return 0;
+}
+
+/* If arg is given, exit without errors. This happens on command 'quit' */
+
+static int
+com_quit(String *buffer __attribute__((unused)),
+ char *line __attribute__((unused)))
+{
+ status.exit_status=0;
+ return 1;
+}
+
+static int
+com_rehash(String *buffer __attribute__((unused)),
+ char *line __attribute__((unused)))
+{
+#ifdef HAVE_READLINE
+ build_completion_hash(0,0);
+#endif
+ return 0;
+}
+
+static int
+com_print(String *buffer,char *line __attribute__((unused)))
+{
+ puts("--------------");
+ (void) fputs(buffer->c_ptr(),stdout);
+ if (!buffer->length() || (*buffer)[buffer->length()-1] != '\n')
+ putchar('\n');
+ puts("--------------\n");
+ return 0; /* If empty buffer */
+}
+
+ /* ARGSUSED */
+static int
+com_connect(String *buffer, char *line)
+{
+ char *tmp,buff[256];
+ bool save_rehash=no_rehash;
+ int error;
+
+ if (buffer)
+ {
+ while (isspace(*line))
+ line++;
+ strnmov(buff,line,sizeof(buff)-1); // Don't destroy history
+ if (buff[0] == '\\') // Short command
+ buff[1]=' ';
+ tmp=(char *) strtok(buff," \t"); // Skipp connect command
+ if (tmp && (tmp=(char *) strtok(NullS," \t;")))
+ {
+ my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
+ current_db=my_strdup(tmp,MYF(MY_WME));
+ if ((tmp=(char *) strtok(NullS," \t;")))
+ {
+ my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
+ current_host=my_strdup(tmp,MYF(MY_WME));
+ }
+ }
+ else
+ no_rehash=1; // Quick re-connect
+ buffer->length(0); // command used
+ }
+ else
+ no_rehash=1;
+ error=sql_connect(current_host,current_db,current_user,opt_password,0);
+ no_rehash=save_rehash;
+
+ if (connected)
+ {
+ sprintf(buff,"Connection id: %ld",mysql_thread_id(&mysql));
+ put_info(buff,INFO_INFO);
+ sprintf(buff,"Current database: %s\n",
+ current_db ? current_db : "*** NO ONE ***");
+ put_info(buff,INFO_INFO);
+ }
+ return error;
+}
+
+
+static int com_source(String *buffer, char *line)
+{
+ char source_name[FN_REFLEN], *end, *param;
+ LINE_BUFFER *line_buff;
+ int error;
+ STATUS old_status;
+ FILE *sql_file;
+
+ /* Skip space from file name */
+ while (isspace(*line))
+ line++;
+ if (!(param = strchr(line, ' '))) // Skipp command name
+ return put_info("Usage: \\. <filename> | source <filename>", INFO_ERROR, 0);
+ while (isspace(*param))
+ param++;
+ end=strmake(source_name,param,sizeof(source_name)-1);
+ while (end > source_name && (isspace(end[-1]) || iscntrl(end[-1])))
+ end--;
+ end[0]=0;
+ /* open file name */
+ if (!(sql_file = my_fopen(source_name, O_RDONLY,MYF(0))))
+ {
+ char buff[FN_REFLEN+60];
+ sprintf(buff,"Failed to open file '%s', error: %d", source_name,errno);
+ return put_info(buff, INFO_ERROR, 0);
+ }
+
+ if (!(line_buff=batch_readline_init(max_allowed_packet+512,sql_file)))
+ {
+ my_fclose(sql_file,MYF(0));
+ return put_info("Can't initialize batch_readline", INFO_ERROR, 0);
+ }
+
+ /* Save old status */
+ old_status=status;
+ bfill((char*) &status,sizeof(status),(char) 0);
+
+ status.batch=old_status.batch; // Run in batch mode
+ status.line_buff=line_buff;
+ status.file_name=source_name;
+ glob_buffer.length(0); // Empty command buffer
+ error=read_lines(0); // Read lines from file
+ status=old_status; // Continue as before
+ my_fclose(sql_file,MYF(0));
+ batch_readline_end(line_buff);
+ return error;
+}
+
+
+ /* ARGSUSED */
+static int
+com_use(String *buffer __attribute__((unused)), char *line)
+{
+ char *tmp;
+ char buff[256];
+
+ while (isspace(*line))
+ line++;
+ strnmov(buff,line,sizeof(buff)-1); // Don't destroy history
+ if (buff[0] == '\\') // Short command
+ buff[1]=' ';
+ tmp=(char *) strtok(buff," \t;"); // Skipp connect command
+ if (!tmp || !(tmp=(char *) strtok(NullS," \t;")))
+ {
+ put_info("USE must be followed by a database name",INFO_ERROR);
+ return 0;
+ }
+ if (!current_db || cmp_database(current_db,tmp))
+ {
+ if (one_database)
+ skip_updates=1;
+ else
+ {
+ /*
+ reconnect once if connection is down or if connection was found to
+ be down during query
+ */
+ if (!connected && reconnect())
+ return status.batch ? 1 : -1; // Fatal error
+ if (mysql_select_db(&mysql,tmp))
+ {
+ if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR)
+ return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
+
+ if (reconnect())
+ return status.batch ? 1 : -1; // Fatal error
+ if (mysql_select_db(&mysql,tmp))
+ return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
+ }
+#ifdef HAVE_READLINE
+ build_completion_hash(no_rehash,1);
+#endif
+ my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
+ current_db=my_strdup(tmp,MYF(MY_WME));
+ }
+ }
+ else
+ skip_updates=0;
+ put_info("Database changed",INFO_INFO);
+ return 0;
+}
+
+
+static int
+sql_real_connect(char *host,char *database,char *user,char *password,
+ uint silent)
+{
+ if (connected)
+ { /* if old is open, close it first */
+ mysql_close(&mysql);
+ connected= 0;
+ }
+ mysql_init(&mysql);
+ if (opt_compress)
+ mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath);
+#endif
+ if (safe_updates)
+ {
+ char init_command[100];
+ sprintf(init_command,
+ "SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=%lu,SQL_MAX_JOIN_SIZE=%lu",
+ select_limit,max_join_size);
+ mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command);
+ }
+ if (!mysql_real_connect(&mysql,host,user,password,
+ database,opt_mysql_port,opt_mysql_unix_port,
+ connect_flag))
+ {
+ if (!silent ||
+ (mysql_errno(&mysql) != CR_CONN_HOST_ERROR &&
+ mysql_errno(&mysql) != CR_CONNECTION_ERROR))
+ {
+ put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
+ (void) fflush(stdout);
+ return ignore_errors ? -1 : 1; // Abort
+ }
+ return -1; // Retryable
+ }
+ connected=1;
+ mysql.reconnect=info_flag ? 1 : 0; // We want to know if this happens
+#ifdef HAVE_READLINE
+ build_completion_hash(no_rehash,1);
+#endif
+ return 0;
+}
+
+
+static int
+sql_connect(char *host,char *database,char *user,char *password,uint silent)
+{
+ bool message=0;
+ uint count=0;
+ int error;
+ for (;;)
+ {
+ if ((error=sql_real_connect(host,database,user,password,wait_flag)) >= 0)
+ {
+ if (count)
+ {
+ fputs("\n",stderr);
+ (void) fflush(stderr);
+ }
+ return error;
+ }
+ if (!wait_flag)
+ return ignore_errors ? -1 : 1;
+ if (!message && !silent)
+ {
+ message=1;
+ fputs("Waiting",stderr); (void) fflush(stderr);
+ }
+ (void) sleep(5);
+ if (!silent)
+ {
+ putc('.',stderr); (void) fflush(stderr);
+ count++;
+ }
+ }
+}
+
+
+
+static int
+com_status(String *buffer __attribute__((unused)),
+ char *line __attribute__((unused)))
+{
+ char *status;
+ puts("--------------");
+ usage(1); /* Print version */
+ if (connected)
+ {
+ MYSQL_RES *result;
+ LINT_INIT(result);
+ printf("\nConnection id:\t\t%ld\n",mysql_thread_id(&mysql));
+ if (!mysql_query(&mysql,"select DATABASE(),USER()") &&
+ (result=mysql_use_result(&mysql)))
+ {
+ MYSQL_ROW cur=mysql_fetch_row(result);
+ printf("Current database:\t%s\n",cur[0]);
+ printf("Current user:\t\t%s\n",cur[1]);
+ (void) mysql_fetch_row(result); // Read eof
+ }
+ }
+ else
+ {
+ vidattr(A_BOLD);
+ printf("\nNo connection\n");
+ vidattr(A_NORMAL);
+ return 0;
+ }
+ if (skip_updates)
+ {
+ vidattr(A_BOLD);
+ printf("\nAll updates ignored to this database\n");
+ vidattr(A_NORMAL);
+ }
+ printf("Server version\t\t%s\n", mysql_get_server_info(&mysql));
+ printf("Protocol version\t%d\n", mysql_get_proto_info(&mysql));
+ printf("Connection\t\t%s\n", mysql_get_host_info(&mysql));
+ printf("Language\t\t%s\n", mysql.charset->name);
+ if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || ! mysql.unix_socket)
+ printf("TCP port\t\t%d\n", mysql.port);
+ else
+ printf("UNIX socket\t\t%s\n", mysql.unix_socket);
+ if ((status=mysql_stat(&mysql)) && !mysql_error(&mysql)[0])
+ {
+ char *pos,buff[40];
+ ulong sec;
+ pos=strchr(status,' ');
+ *pos++=0;
+ printf("%s\t\t\t",status); /* print label */
+ if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec)))
+ {
+ nice_time((double) sec,buff,0);
+ puts(buff); /* print nice time */
+ while (*status == ' ') status++; /* to next info */
+ }
+ if (status)
+ {
+ putchar('\n');
+ puts(status);
+ }
+ }
+ if (safe_updates)
+ {
+ vidattr(A_BOLD);
+ printf("\nNote that we are running in safe_update_mode:\n");
+ vidattr(A_NORMAL);
+ printf("\
+UPDATE and DELETE that doesn't use a key in the WHERE clause are not allowed\n\
+(One can force UPDATE/DELETE by adding LIMIT # at the end of the command)\n\
+SELECT has an automatic 'LIMIT %lu' if LIMIT is not used\n\
+Max number of examined row combination in a join is set to: %lu\n\n",
+select_limit,max_join_size);
+ }
+ puts("--------------\n");
+ return 0;
+}
+
+
+static int
+put_info(const char *str,INFO_TYPE info_type,uint error)
+{
+ static int inited=0;
+
+ if (status.batch)
+ {
+ if (info_type == INFO_ERROR)
+ {
+ (void) fflush(stdout);
+ fprintf(stderr,"ERROR");
+ if (error)
+ (void) fprintf(stderr," %d",error);
+ if (status.query_start_line && ! skip_line_numbers)
+ {
+ (void) fprintf(stderr," at line %lu",status.query_start_line);
+ if (status.file_name)
+ (void) fprintf(stderr," in file: '%s'", status.file_name);
+ }
+ (void) fprintf(stderr,": %s\n",str);
+ (void) fflush(stderr);
+ if (!ignore_errors)
+ return 1;
+ }
+ else if (info_type == INFO_RESULT && verbose > 1)
+ puts(str);
+ if (unbuffered)
+ fflush(stdout);
+ return info_type == INFO_ERROR ? -1 : 0;
+ }
+ if (!opt_silent || info_type == INFO_ERROR)
+ {
+ if (!inited)
+ {
+ inited=1;
+#ifdef HAVE_SETUPTERM
+ (void) setupterm((char *)0, 1, (int *) 0);
+#endif
+ }
+ if (info_type == INFO_ERROR)
+ {
+ putchar('\007'); /* This should make a bell */
+ vidattr(A_STANDOUT);
+ if (error)
+ (void) fprintf(stderr,"ERROR %d: ",error);
+ else
+ fputs("ERROR: ",stdout);
+ }
+ else
+ vidattr(A_BOLD);
+ (void) puts(str);
+ vidattr(A_NORMAL);
+ }
+ if (unbuffered)
+ fflush(stdout);
+ return info_type == INFO_ERROR ? -1 : 0;
+}
+
+static void remove_cntrl(String &buffer)
+{
+ char *start,*end;
+ end=(start=(char*) buffer.ptr())+buffer.length();
+ while (start < end && !isgraph(end[-1]))
+ end--;
+ buffer.length((uint) (end-start));
+}
+
+
+#ifdef __WIN__
+#include <time.h>
+#else
+#include <sys/times.h>
+#undef CLOCKS_PER_SEC
+#define CLOCKS_PER_SEC (sysconf(_SC_CLK_TCK))
+#endif
+
+static ulong start_timer(void)
+{
+#ifdef __WIN__
+ return clock();
+#else
+ struct tms tms_tmp;
+ return times(&tms_tmp);
+#endif
+}
+
+
+static void nice_time(double sec,char *buff,bool part_second)
+{
+ ulong tmp;
+ if (sec >= 3600.0*24)
+ {
+ tmp=(ulong) floor(sec/(3600.0*24));
+ sec-=3600.0*24*tmp;
+ buff=int2str((long) tmp,buff,10);
+ buff=strmov(buff,tmp > 1 ? " days " : " day ");
+ }
+ if (sec >= 3600.0)
+ {
+ tmp=(ulong) floor(sec/3600.0);
+ sec-=3600.0*tmp;
+ buff=int2str((long) tmp,buff,10);
+ buff=strmov(buff,tmp > 1 ? " hours " : " hour ");
+ }
+ if (sec >= 60.0)
+ {
+ tmp=(ulong) floor(sec/60.0);
+ sec-=60.0*tmp;
+ buff=int2str((long) tmp,buff,10);
+ buff=strmov(buff," min ");
+ }
+ if (part_second)
+ sprintf(buff,"%.2f sec",sec);
+ else
+ sprintf(buff,"%d sec",(int) sec);
+}
+
+
+static void end_timer(ulong start_time,char *buff)
+{
+ nice_time((double) (start_timer() - start_time) /
+ CLOCKS_PER_SEC,buff,1);
+}
+
+
+static void mysql_end_timer(ulong start_time,char *buff)
+{
+ buff[0]=' ';
+ buff[1]='(';
+ end_timer(start_time,buff+2);
+ strmov(strend(buff),")");
+}
+
+/* Keep sql_string library happy */
+
+gptr sql_alloc(unsigned int Size)
+{
+ return my_malloc(Size,MYF(MY_WME));
+}
+
+void sql_element_free(void *ptr)
+{
+ my_free((gptr) ptr,MYF(0));
+}
diff --git a/client/mysqladmin.c b/client/mysqladmin.c
new file mode 100644
index 00000000000..62c01fc1bfd
--- /dev/null
+++ b/client/mysqladmin.c
@@ -0,0 +1,1099 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* maintaince of mysql databases */
+
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <signal.h>
+#include "mysql.h"
+#include "errmsg.h"
+#include <getopt.h>
+#ifdef THREAD
+#include <my_pthread.h> /* because of signal() */
+#endif
+
+#define ADMIN_VERSION "8.8"
+#define MAX_MYSQL_VAR 64
+#define MAX_TIME_TO_WAIT 3600 /* Wait for shutdown */
+#define MAX_TRUNC_LENGTH 3
+
+char truncated_var_names[MAX_MYSQL_VAR][MAX_TRUNC_LENGTH];
+char ex_var_names[MAX_MYSQL_VAR][FN_REFLEN];
+ulonglong last_values[MAX_MYSQL_VAR];
+static int interval=0;
+static my_bool option_force=0,interrupted=0,new_line=0,option_silent=0,
+ opt_compress=0, opt_relative=0, opt_verbose=0, opt_vertical=0;
+static uint tcp_port = 0, option_wait = 0;
+static my_string unix_port=0;
+
+/* When using extended-status relatively, ex_val_max_len is the estimated
+ maximum length for any relative value printed by extended-status. The
+ idea is to try to keep the length of output as short as possible. */
+static uint ex_val_max_len[MAX_MYSQL_VAR];
+static my_bool ex_status_printed = 0; /* First output is not relative. */
+static uint ex_var_count, max_var_length, max_val_length;
+
+#include "sslopt-vars.h"
+
+static void print_version(void);
+static void usage(void);
+static my_bool sql_connect(MYSQL *mysql,const char *host, const char *user,
+ const char *password,uint wait);
+static my_bool execute_commands(MYSQL *mysql,int argc, char **argv);
+static int drop_db(MYSQL *mysql,const char *db);
+static sig_handler endprog(int signal_number);
+static void nice_time(ulong sec,char *buff);
+static void print_header(MYSQL_RES *result);
+static void print_top(MYSQL_RES *result);
+static void print_row(MYSQL_RES *result,MYSQL_ROW cur, uint row);
+static void print_relative_row(MYSQL_RES *result, MYSQL_ROW cur, uint row);
+static void print_relative_row_vert(MYSQL_RES *result, MYSQL_ROW cur, uint row);
+static void print_relative_header();
+static void print_relative_line();
+static void truncate_names();
+static my_bool get_pidfile(MYSQL *mysql, char *pidfile);
+static void wait_pidfile(char *pidfile);
+static void store_values(MYSQL_RES *result);
+
+/*
+ The order of commands must be the same as command_names,
+ except ADMIN_ERROR
+*/
+enum commands { ADMIN_ERROR, ADMIN_CREATE, ADMIN_DROP, ADMIN_SHUTDOWN,
+ ADMIN_RELOAD, ADMIN_REFRESH, ADMIN_VER, ADMIN_PROCESSLIST,
+ ADMIN_STATUS, ADMIN_KILL, ADMIN_DEBUG, ADMIN_VARIABLES,
+ ADMIN_FLUSH_LOGS, ADMIN_FLUSH_HOSTS, ADMIN_FLUSH_TABLES,
+ ADMIN_PASSWORD, ADMIN_PING, ADMIN_EXTENDED_STATUS,
+ ADMIN_FLUSH_STATUS, ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE,
+ ADMIN_STOP_SLAVE, ADMIN_FLUSH_THREADS
+};
+static const char *command_names[]=
+{"create","drop","shutdown","reload","refresh",
+ "version", "processlist","status","kill","debug",
+ "variables","flush-logs","flush-hosts",
+ "flush-tables","password","ping",
+ "extended-status","flush-status",
+ "flush-privileges", "start-slave","stop-slave", "flush-threads", NullS};
+static TYPELIB command_typelib=
+{ array_elements(command_names)-1,"commands", command_names};
+
+enum options { OPT_CHARSETS_DIR=256 };
+
+static struct option long_options[] =
+{
+ {"compress", no_argument, 0, 'C'},
+ {"character-sets-dir",required_argument, 0, OPT_CHARSETS_DIR},
+ {"debug", optional_argument, 0, '#'},
+ {"force", no_argument, 0, 'f'},
+ {"help", no_argument, 0, '?'},
+ {"host", required_argument, 0, 'h'},
+ {"password", optional_argument, 0, 'p'},
+#ifdef __WIN__
+ {"pipe", no_argument, 0, 'W'},
+#endif
+ {"port", required_argument, 0, 'P'},
+ {"relative", no_argument, 0, 'r'},
+ {"silent", no_argument, 0, 's'},
+ {"socket", required_argument, 0, 'S'},
+ {"sleep", required_argument, 0, 'i'},
+#include "sslopt-longopts.h"
+ {"timeout", required_argument, 0, 't'},
+#ifndef DONT_ALLOW_USER_CHANGE
+ {"user", required_argument, 0, 'u'},
+#endif
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"vertical", no_argument, 0, 'E'},
+ {"wait", optional_argument, 0, 'w'},
+ {0, 0, 0, 0}
+};
+
+static const char *load_default_groups[]= { "mysqladmin","client",0 };
+
+int main(int argc,char *argv[])
+{
+ int c, error = 0,option_index=0;
+ MYSQL mysql;
+ char *host = NULL,*password=0,*user=0,**commands;
+ my_bool tty_password=0;
+ MY_INIT(argv[0]);
+ mysql_init(&mysql);
+ load_defaults("my",load_default_groups,&argc,&argv);
+
+ while ((c=getopt_long(argc,argv,"h:i:p::u:#::P:sS:Ct:fq?vVw::WrE",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'C':
+ opt_compress=1;
+ break;
+ case 'h':
+ host = optarg;
+ break;
+ case 'q': /* Allow old 'q' option */
+ case 'f':
+ option_force++;
+ break;
+ case 'p':
+ if (optarg)
+ {
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ password=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ }
+ else
+ tty_password=1;
+ break;
+#ifndef DONT_ALLOW_USER_CHANGE
+ case 'u':
+ user= my_strdup(optarg,MYF(0));
+ break;
+#endif
+ case 'i':
+ interval=atoi(optarg);
+ break;
+ case 'P':
+ tcp_port= (unsigned int) atoi(optarg);
+ break;
+ case 'r':
+ opt_relative = 1;
+ break;
+ case 'E':
+ opt_vertical = 1;
+ break;
+ case 's':
+ option_silent = 1;
+ break;
+ case 'S':
+ unix_port= optarg;
+ break;
+ case 'W':
+#ifdef __WIN__
+ unix_port=MYSQL_NAMEDPIPE;
+#endif
+ break;
+ case 't':
+ {
+ uint tmp=atoi(optarg);
+ mysql_options(&mysql,MYSQL_OPT_CONNECT_TIMEOUT, (char*) &tmp);
+ break;
+ }
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o,/tmp/mysqladmin.trace");
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ break;
+ case 'v':
+ opt_verbose=1;
+ break;
+ case 'w':
+ if (optarg)
+ {
+ if ((option_wait=atoi(optarg)) <= 0)
+ option_wait=1;
+ }
+ else
+ option_wait= ~0;
+ break;
+#include "sslopt-case.h"
+ default:
+ fprintf(stderr,"Illegal option character '%c'\n",opterr);
+ /* Fall throught */
+ case '?':
+ case 'I': /* Info */
+ error++;
+ break;
+ case OPT_CHARSETS_DIR:
+#if MYSQL_VERSION_ID > 32300
+ charsets_dir = optarg;
+#endif
+ break;
+ }
+ }
+ argc -= optind;
+ commands = argv + optind;
+ if (error || argc == 0)
+ {
+ usage();
+ exit(1);
+ }
+ if (tty_password)
+ password = get_tty_password(NullS);
+
+ VOID(signal(SIGINT,endprog)); /* Here if abort */
+ VOID(signal(SIGTERM,endprog)); /* Here if abort */
+
+ mysql_init(&mysql);
+ if (opt_compress)
+ mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath);
+#endif /* HAVE_OPENSSL */
+ if (sql_connect(&mysql,host,user,password,option_wait))
+ error = 1;
+ else
+ {
+ error = 0;
+ while (!interrupted)
+ {
+ new_line = 0;
+ if (execute_commands(&mysql,argc,commands) && !option_force)
+ {
+ if (option_wait && !interrupted)
+ {
+ mysql_close(&mysql);
+ if (!sql_connect(&mysql,host,user,password,option_wait))
+ continue; /* Retry */
+ }
+ error=1;
+ break;
+ }
+ if (interval)
+ {
+ sleep(interval);
+ if (new_line)
+ puts("");
+ }
+ else
+ break;
+ }
+ mysql_close(&mysql);
+ }
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(user,MYF(MY_ALLOW_ZERO_PTR));
+ free_defaults(argv);
+ my_end(0);
+ exit(error);
+ return 0;
+}
+
+
+static sig_handler endprog(int signal_number __attribute__((unused)))
+{
+ interrupted=1;
+}
+
+
+static my_bool sql_connect(MYSQL *mysql,const char *host, const char *user,
+ const char *password,uint wait)
+{
+ my_bool info=0;
+
+ for (;;)
+ {
+ if (mysql_real_connect(mysql,host,user,password,NullS,tcp_port,unix_port,
+ 0))
+ {
+ if (info)
+ {
+ fputs("\n",stderr);
+ (void) fflush(stderr);
+ }
+ return 0;
+ }
+
+ if (!wait)
+ {
+ if (!option_silent)
+ {
+ if (!host)
+ host=LOCAL_HOST;
+ my_printf_error(0,"connect to server at '%s' failed\nerror: '%s'",
+ MYF(ME_BELL), host, mysql_error(mysql));
+ if (mysql_errno(mysql) == CR_CONNECTION_ERROR)
+ {
+ fprintf(stderr,
+ "Check that mysqld is running and that the socket: '%s' exists!\n",
+ unix_port ? unix_port : mysql_unix_port);
+ }
+ else if (mysql_errno(mysql) == CR_CONN_HOST_ERROR ||
+ mysql_errno(mysql) == CR_UNKNOWN_HOST)
+ {
+ fprintf(stderr,"Check that mysqld is running on %s",host);
+ fprintf(stderr," and that the port is %d.\n",
+ tcp_port ? tcp_port: mysql_port);
+ fprintf(stderr,"You can check this by doing 'telnet %s %d'\n",
+ host, tcp_port ? tcp_port: mysql_port);
+ }
+ }
+ return 1;
+ }
+ if (wait != (uint) ~0)
+ wait--; /* One less retry */
+ if ((mysql_errno(mysql) != CR_CONN_HOST_ERROR) &&
+ (mysql_errno(mysql) != CR_CONNECTION_ERROR))
+ {
+ fprintf(stderr,"Got error: %s\n", mysql_error(mysql));
+ if (!option_force)
+ return 1;
+ sleep(5);
+ }
+ else if (!info)
+ {
+ info=1;
+ fputs("Waiting for MySQL server to answer",stderr);
+ (void) fflush(stderr);
+ sleep(5);
+ }
+ else
+ {
+ putc('.',stderr);
+ (void) fflush(stderr);
+ sleep(5);
+ }
+ }
+}
+
+
+static my_bool execute_commands(MYSQL *mysql,int argc, char **argv)
+{
+ char *status;
+
+ for (; argc > 0 ; argv++,argc--)
+ {
+ switch (find_type(argv[0],&command_typelib,2)) {
+ case ADMIN_CREATE:
+ {
+ char buff[FN_REFLEN+20];
+ if (argc < 2)
+ {
+ my_printf_error(0,"Too few arguments to create",MYF(ME_BELL));
+ return 1;
+ }
+ sprintf(buff,"create database %.*s",FN_REFLEN,argv[1]);
+ if (mysql_query(mysql,buff))
+ return 1;
+ else
+ {
+ argc--; argv++;
+ }
+ break;
+ }
+ case ADMIN_DROP:
+ {
+ if (argc < 2)
+ {
+ my_printf_error(0,"Too few arguments to drop",MYF(ME_BELL));
+ return 1;
+ }
+ if (drop_db(mysql,argv[1]))
+ return 1;
+ else
+ {
+ argc--; argv++;
+ }
+ break;
+ }
+ case ADMIN_SHUTDOWN:
+ {
+ char pidfile[FN_REFLEN];
+ my_bool got_pidfile=0;
+ /* Only wait for pidfile on local connections */
+ /* If pidfile doesn't exist, continue without pid file checking */
+ if (mysql->unix_socket)
+ got_pidfile= !get_pidfile(mysql, pidfile);
+ if (mysql_shutdown(mysql))
+ {
+ my_printf_error(0,"shutdown failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ mysql_close(mysql); /* Close connection to avoid error messages */
+ if (got_pidfile)
+ {
+ if (opt_verbose)
+ printf("Shutdown signal sent to server; Waiting for pid file to disappear\n");
+ wait_pidfile(pidfile); /* Wait until pid file is gone */
+ }
+ break;
+ }
+ case ADMIN_FLUSH_PRIVILEGES:
+ case ADMIN_RELOAD:
+ if (mysql_refresh(mysql,REFRESH_GRANT) < 0)
+ {
+ my_printf_error(0,"reload failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ case ADMIN_REFRESH:
+ if (mysql_refresh(mysql,
+ (uint) ~(REFRESH_GRANT | REFRESH_STATUS |
+ REFRESH_READ_LOCK)) < 0)
+ {
+ my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ case ADMIN_FLUSH_THREADS:
+ if (mysql_refresh(mysql,(uint) REFRESH_THREADS) < 0)
+ {
+ my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ case ADMIN_VER:
+ new_line=1;
+ print_version();
+ puts("TCX Datakonsult AB, by Monty\n");
+ printf("Server version\t\t%s\n", mysql_get_server_info(mysql));
+ printf("Protocol version\t%d\n", mysql_get_proto_info(mysql));
+ printf("Connection\t\t%s\n",mysql_get_host_info(mysql));
+ if (mysql->unix_socket)
+ printf("UNIX socket\t\t%s\n", mysql->unix_socket);
+ else
+ printf("TCP port\t\t%d\n", mysql->port);
+ status=mysql_stat(mysql);
+ {
+ char *pos,buff[40];
+ ulong sec;
+ pos=strchr(status,' ');
+ *pos++=0;
+ printf("%s\t\t\t",status); /* print label */
+ if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec)))
+ {
+ nice_time(sec,buff);
+ puts(buff); /* print nice time */
+ while (*status == ' ') status++; /* to next info */
+ }
+ }
+ putc('\n',stdout);
+ if (status)
+ puts(status);
+ break;
+ case ADMIN_PROCESSLIST:
+ {
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ if (mysql_query(mysql, (opt_verbose ? "show full processlist" :
+ "show processlist")) ||
+ !(result = mysql_store_result(mysql)))
+ {
+ my_printf_error(0,"process list failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ print_header(result);
+ while ((row=mysql_fetch_row(result)))
+ print_row(result,row,0);
+ print_top(result);
+ mysql_free_result(result);
+ new_line=1;
+ break;
+ }
+ case ADMIN_STATUS:
+ status=mysql_stat(mysql);
+ if (status)
+ puts(status);
+ break;
+ case ADMIN_KILL:
+ {
+ uint error=0;
+ char *pos;
+ if (argc < 2)
+ {
+ my_printf_error(0,"Too few arguments to 'kill'",MYF(ME_BELL));
+ return 1;
+ }
+ pos=argv[1];
+ for (;;)
+ {
+ if (mysql_kill(mysql,(ulong) atol(pos)))
+ {
+ my_printf_error(0,"kill failed on %ld; error: '%s'",MYF(ME_BELL),
+ atol(pos), mysql_error(mysql));
+ error=1;
+ }
+ if (!(pos=strchr(pos,',')))
+ break;
+ pos++;
+ }
+ argc--; argv++;
+ if (error)
+ return error;
+ break;
+ }
+ case ADMIN_DEBUG:
+ if (mysql_dump_debug_info(mysql))
+ {
+ my_printf_error(0,"debug failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ case ADMIN_VARIABLES:
+ {
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+
+ new_line=1;
+ if (mysql_query(mysql,"show variables") ||
+ !(res=mysql_store_result(mysql)))
+ {
+ my_printf_error(0,"unable to show variables; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ print_header(res);
+ while ((row=mysql_fetch_row(res)))
+ print_row(res,row,0);
+ print_top(res);
+ mysql_free_result(res);
+ break;
+ }
+ case ADMIN_EXTENDED_STATUS:
+ {
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ uint rownr = 0;
+ void (*func) (MYSQL_RES*, MYSQL_ROW, uint);
+
+ new_line = 1;
+ if (mysql_query(mysql, "show status") ||
+ !(res = mysql_store_result(mysql)))
+ {
+ my_printf_error(0, "unable to show status; error: '%s'", MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ if (!opt_vertical)
+ print_header(res);
+ else
+ {
+ if (!ex_status_printed)
+ {
+ store_values(res);
+ truncate_names(); /* Does some printing also */
+ }
+ else
+ {
+ print_relative_line();
+ print_relative_header();
+ print_relative_line();
+ }
+ }
+
+ /* void (*func) (MYSQL_RES*, MYSQL_ROW, uint); */
+ if (opt_relative && !opt_vertical)
+ func = print_relative_row;
+ else if (opt_vertical)
+ func = print_relative_row_vert;
+ else
+ func = print_row;
+
+ while ((row = mysql_fetch_row(res)))
+ (*func)(res, row, rownr++);
+ if (opt_vertical)
+ {
+ if (ex_status_printed)
+ {
+ putchar('\n');
+ print_relative_line();
+ }
+ }
+ else
+ print_top(res);
+
+ ex_status_printed = 1; /* From now on the output will be relative */
+ mysql_free_result(res);
+ break;
+ }
+ case ADMIN_FLUSH_LOGS:
+ {
+ if (mysql_refresh(mysql,REFRESH_LOG))
+ {
+ my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ }
+ case ADMIN_FLUSH_HOSTS:
+ {
+ if (mysql_refresh(mysql,REFRESH_HOSTS))
+ {
+ my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ }
+ case ADMIN_FLUSH_TABLES:
+ {
+ if (mysql_refresh(mysql,REFRESH_TABLES))
+ {
+ my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ }
+ case ADMIN_FLUSH_STATUS:
+ {
+ if (mysql_refresh(mysql,REFRESH_STATUS))
+ {
+ my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ }
+ case ADMIN_PASSWORD:
+ {
+ char buff[128],crypted_pw[33];
+
+ if(argc < 2)
+ {
+ my_printf_error(0,"Too few arguments to change password",MYF(ME_BELL));
+ return 1;
+ }
+ if (argv[1][0])
+ make_scrambled_password(crypted_pw,argv[1]);
+ else
+ crypted_pw[0]=0; /* No password */
+ sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw);
+
+ if (mysql_query(mysql,"set sql_log_off=1"))
+ {
+ my_printf_error(0, "Can't turn off logging; error: '%s'",
+ MYF(ME_BELL),mysql_error(mysql));
+ return 1;
+ }
+ if (mysql_query(mysql,buff))
+ {
+ my_printf_error(0,"unable to change password; error: '%s'",
+ MYF(ME_BELL),mysql_error(mysql));
+ return 1;
+ }
+ argc--; argv++;
+ break;
+ }
+
+ case ADMIN_START_SLAVE:
+ if (mysql_query(mysql, "SLAVE START"))
+ {
+ my_printf_error(0, "Error starting slave: %s", MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ else
+ puts("Slave started");
+ break;
+ case ADMIN_STOP_SLAVE:
+ if (mysql_query(mysql, "SLAVE STOP"))
+ {
+ my_printf_error(0, "Error stopping slave: %s", MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ else
+ puts("Slave stopped");
+ break;
+
+ case ADMIN_PING:
+ mysql->reconnect=0; /* We want to know of reconnects */
+ if (!mysql_ping(mysql))
+ puts("mysqld is alive");
+ else
+ {
+ if (mysql_errno(mysql) == CR_SERVER_GONE_ERROR)
+ {
+ mysql->reconnect=1;
+ if (!mysql_ping(mysql))
+ puts("connection was down, but mysqld is now alive");
+ }
+ else
+ {
+ my_printf_error(0,"mysqld doesn't answer to ping, error: '%s'",
+ MYF(ME_BELL),mysql_error(mysql));
+ return 1;
+ }
+ }
+ mysql->reconnect=1; /* Automatic reconnect is default */
+ break;
+ default:
+ my_printf_error(0,"Unknown command: '%s'",MYF(ME_BELL),argv[0]);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s on %s\n",my_progname,ADMIN_VERSION,
+ MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+
+static void usage(void)
+{
+ print_version();
+ puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB");
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
+ puts("Administer program for the mysqld demon");
+ printf("Usage: %s [OPTIONS] command command....\n", my_progname);
+ printf("\n\
+ -#, --debug=... Output debug log. Often this is 'd:t:o,filename`\n\
+ -f, --force Don't ask for confirmation on drop database; with\n\
+ multiple commands, continue even if an error occurs\n\
+ -?, --help Display this help and exit\n\
+ --character-sets-dir=...\n\
+ Set the character set directory\n\
+ -C, --compress Use compression in server/client protocol\n\
+ -h, --host=# Connect to host\n\
+ -p, --password[=...] Password to use when connecting to server\n\
+ If password is not given it's asked from the tty\n");
+#ifdef __WIN__
+ puts("-W, --pipe Use named pipes to connect to server");
+#endif
+ printf("\
+ -P --port=... Port number to use for connection\n\
+ -i, --sleep=sec Execute commands again and again with a sleep between\n\
+ -r, --relative Show difference between current and previous values\n\
+ when used with -i. Currently works only with\n\
+ extended-status\n\
+ -E, --vertical Print output vertically. Is similar to --relative,\n\
+ but prints output vertically.\n\
+ -s, --silent Silently exit if one can't connect to server\n\
+ -S, --socket=... Socket file to use for connection\n");
+#include "sslopt-usage.h"
+ printf("\
+ -t, --timeout=... Timeout for connection to the mysqld server\n");
+#ifndef DONT_ALLOW_USER_CHANGE
+ printf("\
+ -u, --user=# User for login if not current user\n");
+#endif
+ printf("\
+ -v, --verbose Write more information\n\
+ -V, --version Output version information and exit\n\
+ -w, --wait[=retries] Wait and retry if connection is down\n");
+ print_defaults("my",load_default_groups);
+
+ puts("\nWhere command is a one or more of: (Commands may be shortened)\n\
+ create databasename Create a new database\n\
+ drop databasename Delete a database and all its tables\n\
+ extended-status Gives an extended status message from the server\n\
+ flush-hosts Flush all cached hosts\n\
+ flush-logs Flush all logs\n\
+ flush-status Clear status variables\n\
+ flush-tables Flush all tables\n\
+ flush-threads Flush the thread cache\n\
+ flush-privileges Reload grant tables (same as reload)\n\
+ kill id,id,... Kill mysql threads");
+#if MYSQL_VERSION_ID >= 32200
+ puts("\
+ password new-password Change old password to new-password");
+#endif
+ puts("\
+ ping Check if mysqld is alive\n\
+ processlist Show list of active threads in server\n\
+ reload Reload grant tables\n\
+ refresh Flush all tables and close and open logfiles\n\
+ shutdown Take server down\n\
+ status Gives a short status message from the server\n\
+ variables Prints variables available\n\
+ version Get version info from server");
+}
+
+static int drop_db(MYSQL *mysql, const char *db)
+{
+ char name_buff[FN_REFLEN+20], buf[10];
+ if (!option_force)
+ {
+ puts("Dropping the database is potentially a very bad thing to do.");
+ puts("Any data stored in the database will be destroyed.\n");
+ printf("Do you really want to drop the '%s' database [y/N]\n",db);
+ VOID(fgets(buf,sizeof(buf)-1,stdin));
+ if ((*buf != 'y') && (*buf != 'Y'))
+ {
+ puts("\nOK, aborting database drop!");
+ return -1;
+ }
+ }
+ sprintf(name_buff,"drop database %.*s",FN_REFLEN,db);
+ if (mysql_query(mysql,name_buff))
+ {
+ my_printf_error(0,"drop of '%s' failed;\nerror: '%s'",MYF(ME_BELL),
+ db,mysql_error(mysql));
+ return 1;
+ }
+ printf("Database \"%s\" dropped\n",db);
+ return 0;
+}
+
+
+static void nice_time(ulong sec,char *buff)
+{
+ ulong tmp;
+
+ if (sec >= 3600L*24)
+ {
+ tmp=sec/(3600L*24);
+ sec-=3600L*24*tmp;
+ buff=int2str(tmp,buff,10);
+ buff=strmov(buff,tmp > 1 ? " days " : " day ");
+ }
+ if (sec >= 3600L)
+ {
+ tmp=sec/3600L;
+ sec-=3600L*tmp;
+ buff=int2str(tmp,buff,10);
+ buff=strmov(buff,tmp > 1 ? " hours " : " hour ");
+ }
+ if (sec >= 60)
+ {
+ tmp=sec/60;
+ sec-=60*tmp;
+ buff=int2str(tmp,buff,10);
+ buff=strmov(buff," min ");
+ }
+ strmov(int2str(sec,buff,10)," sec");
+}
+
+
+static void print_header(MYSQL_RES *result)
+{
+ MYSQL_FIELD *field;
+
+ print_top(result);
+ mysql_field_seek(result,0);
+ putchar('|');
+ while ((field = mysql_fetch_field(result)))
+ {
+ printf(" %-*s|",field->max_length+1,field->name);
+ }
+ putchar('\n');
+ print_top(result);
+}
+
+
+static void print_top(MYSQL_RES *result)
+{
+ uint i,length;
+ MYSQL_FIELD *field;
+
+ putchar('+');
+ mysql_field_seek(result,0);
+ while((field = mysql_fetch_field(result)))
+ {
+ if ((length=strlen(field->name)) > field->max_length)
+ field->max_length=length;
+ else
+ length=field->max_length;
+ for (i=length+2 ; i--> 0 ; )
+ putchar('-');
+ putchar('+');
+ }
+ putchar('\n');
+}
+
+
+/* 3.rd argument, uint row, is not in use. Don't remove! */
+static void print_row(MYSQL_RES *result, MYSQL_ROW cur,
+ uint row __attribute__((unused)))
+{
+ uint i,length;
+ MYSQL_FIELD *field;
+
+ putchar('|');
+ mysql_field_seek(result,0);
+ for (i=0 ; i < mysql_num_fields(result); i++)
+ {
+ field = mysql_fetch_field(result);
+ length=field->max_length;
+ printf(" %-*s|",length+1,cur[i] ? (char*) cur[i] : "");
+ }
+ putchar('\n');
+}
+
+
+static void print_relative_row(MYSQL_RES *result, MYSQL_ROW cur, uint row)
+{
+ ulonglong tmp;
+ char buff[22];
+ MYSQL_FIELD *field;
+
+ mysql_field_seek(result, 0);
+ field = mysql_fetch_field(result);
+ printf("| %-*s|", field->max_length + 1, cur[0]);
+
+ field = mysql_fetch_field(result);
+ tmp = cur[1] ? strtoull(cur[1], NULL, 0) : (ulonglong) 0;
+ printf(" %-*s|\n", field->max_length + 1,
+ llstr((tmp - last_values[row]), buff));
+ last_values[row] = tmp;
+}
+
+
+static void print_relative_row_vert(MYSQL_RES *result __attribute__((unused)),
+ MYSQL_ROW cur,
+ uint row __attribute__((unused)))
+{
+ uint length;
+ ulonglong tmp;
+ char buff[22];
+
+ if (!row)
+ putchar('|');
+
+ tmp = cur[1] ? strtoull(cur[1], NULL, 0) : (ulonglong) 0;
+ printf(" %-*s|", ex_val_max_len[row] + 1,
+ llstr((tmp - last_values[row]), buff));
+
+ /* Find the minimum row length needed to output the relative value */
+ if ((length=strlen(buff) > ex_val_max_len[row]) && ex_status_printed)
+ ex_val_max_len[row] = length;
+ last_values[row] = tmp;
+}
+
+
+static void store_values(MYSQL_RES *result)
+{
+ uint i;
+ MYSQL_ROW row;
+ MYSQL_FIELD *field;
+
+ field = mysql_fetch_field(result);
+ max_var_length = field->max_length;
+ field = mysql_fetch_field(result);
+ max_val_length = field->max_length;
+
+ for (i = 0; (row = mysql_fetch_row(result)); i++)
+ {
+ strmov(ex_var_names[i], row[0]);
+ last_values[i]=strtoull(row[1],NULL,10);
+ ex_val_max_len[i]=2; /* Default print width for values */
+ }
+ ex_var_count = i;
+ return;
+}
+
+
+static void print_relative_header()
+{
+ uint i;
+
+ putchar('|');
+ for (i = 0; i < ex_var_count; i++)
+ printf(" %-*s|", ex_val_max_len[i] + 1, truncated_var_names[i]);
+ putchar('\n');
+}
+
+
+static void print_relative_line()
+{
+ uint i;
+
+ putchar('+');
+ for (i = 0; i < ex_var_count; i++)
+ {
+ uint j;
+ for (j = 0; j < ex_val_max_len[i] + 2; j++)
+ putchar('-');
+ putchar('+');
+ }
+ putchar('\n');
+}
+
+
+static void truncate_names()
+{
+ uint i;
+ char *ptr,top_line[MAX_TRUNC_LENGTH+4+NAME_LEN+22+1],buff[22];
+
+ ptr=top_line;
+ *ptr++='+';
+ ptr=strfill(ptr,max_var_length+2,'-');
+ *ptr++='+';
+ ptr=strfill(ptr,MAX_TRUNC_LENGTH+2,'-');
+ *ptr++='+';
+ ptr=strfill(ptr,max_val_length+2,'-');
+ *ptr++='+';
+ *ptr=0;
+ puts(top_line);
+
+ for (i = 0 ; i < ex_var_count; i++)
+ {
+ uint sfx=1,j;
+ printf("| %-*s|", max_var_length + 1, ex_var_names[i]);
+ ptr = ex_var_names[i];
+ /* Make sure no two same truncated names will become */
+ for (j = 0; j < i; j++)
+ if (*truncated_var_names[j] == *ptr)
+ sfx++;
+
+ truncated_var_names[i][0]= *ptr; /* Copy first var char */
+ int10_to_str(sfx, truncated_var_names[i]+1,10);
+ printf(" %-*s|", MAX_TRUNC_LENGTH + 1, truncated_var_names[i]);
+ printf(" %-*s|\n", max_val_length + 1, llstr(last_values[i],buff));
+ }
+ puts(top_line);
+ return;
+}
+
+
+static my_bool get_pidfile(MYSQL *mysql, char *pidfile)
+{
+ MYSQL_RES* result;
+
+ if (mysql_query(mysql, "SHOW VARIABLES LIKE 'pid_file'"))
+ {
+ my_printf_error(0,"query failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ }
+ result = mysql_store_result(mysql);
+ if (result)
+ {
+ strmov(pidfile, mysql_fetch_row(result)[1]);
+ mysql_free_result(result);
+ return 0;
+ }
+ return 1; /* Error */
+}
+
+
+static void wait_pidfile(char *pidfile)
+{
+ char buff[FN_REFLEN];
+ int fd;
+ uint count=0;
+
+ system_filename(buff,pidfile);
+ while ((fd = open(buff, O_RDONLY)) >= 0 && count++ < MAX_TIME_TO_WAIT)
+ {
+ close(fd);
+ sleep(1);
+ }
+ if (fd >= 0)
+ {
+ close(fd);
+ fprintf(stderr,
+ "Warning; Aborted waiting on pid file: '%s' after %d seconds\n",
+ buff, count-1);
+ }
+}
diff --git a/client/mysqldump.c b/client/mysqldump.c
new file mode 100644
index 00000000000..ce687d815d8
--- /dev/null
+++ b/client/mysqldump.c
@@ -0,0 +1,1285 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* mysqldump.c - Dump a tables contents and format to an ASCII file
+**
+** The author's original notes follow :-
+**
+** ******************************************************
+** * *
+** * AUTHOR: Igor Romanenko (igor@frog.kiev.ua) *
+** * DATE: December 3, 1994 *
+** * WARRANTY: None, expressed, impressed, implied *
+** * or other *
+** * STATUS: Public domain *
+** * Adapted and optimized for MySQL by *
+** * Michael Widenius, Sinisa Milivojevic, Jani Tolonen *
+** * -w --where added 9/10/98 by Jim Faucette *
+** * slave code by David Saez Padros <david@ols.es> *
+** * *
+** ******************************************************
+*/
+/* SSL by
+** Andrei Errapart <andreie@no.spam.ee>
+** Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee>
+**/
+
+#define DUMP_VERSION "8.8"
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+
+#include "mysql.h"
+#include "mysql_version.h"
+#include "mysqld_error.h"
+#include <getopt.h>
+
+/* Exit codes */
+
+#define EX_USAGE 1
+#define EX_MYSQLERR 2
+#define EX_CONSCHECK 3
+#define EX_EOM 4
+
+/* index into 'show fields from table' */
+
+#define SHOW_FIELDNAME 0
+#define SHOW_TYPE 1
+#define SHOW_NULL 2
+#define SHOW_DEFAULT 4
+#define SHOW_EXTRA 5
+#define QUOTE_CHAR '`'
+
+static char *add_load_option(char *ptr, const char *object,
+ const char *statement);
+
+static char *field_escape(char *to,const char *from,uint length);
+static my_bool verbose=0,tFlag=0,cFlag=0,dFlag=0,quick=0, extended_insert = 0,
+ lock_tables=0,ignore_errors=0,flush_logs=0,replace=0,
+ ignore=0,opt_drop=0,opt_keywords=0,opt_lock=0,opt_compress=0,
+ opt_delayed=0,create_options=0,opt_quoted=0,opt_databases=0,
+ opt_alldbs=0,opt_create_db=0,opt_first_slave=0;
+static MYSQL mysql_connection,*sock=0;
+static char insert_pat[12 * 1024],*password=0,*current_user=0,
+ *current_host=0,*path=0,*fields_terminated=0,
+ *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0,
+ *where=0, *default_charset;
+static uint opt_mysql_port=0;
+static my_string opt_mysql_unix_port=0;
+static int first_error=0;
+extern ulong net_buffer_length;
+static DYNAMIC_STRING extended_row;
+#include "sslopt-vars.h"
+
+enum options {OPT_FTB=256, OPT_LTB, OPT_ENC, OPT_O_ENC, OPT_ESC, OPT_KEYWORDS,
+ OPT_LOCKS, OPT_DROP, OPT_OPTIMIZE, OPT_DELAYED, OPT_TABLES,
+ OPT_CHARSETS_DIR, OPT_DEFAULT_CHARSET};
+
+static struct option long_options[] =
+{
+ {"all-databases", no_argument, 0, 'A'},
+ {"all", no_argument, 0, 'a'},
+ {"add-drop-table", no_argument, 0, OPT_DROP},
+ {"add-locks", no_argument, 0, OPT_LOCKS},
+ {"allow-keywords", no_argument, 0, OPT_KEYWORDS},
+ {"character-sets-dir",required_argument,0, OPT_CHARSETS_DIR},
+ {"complete-insert", no_argument, 0, 'c'},
+ {"compress", no_argument, 0, 'C'},
+ {"databases", no_argument, 0, 'B'},
+ {"debug", optional_argument, 0, '#'},
+ {"default-character-set", required_argument, 0, OPT_DEFAULT_CHARSET},
+ {"delayed-insert", no_argument, 0, OPT_DELAYED},
+ {"extended-insert", no_argument, 0, 'e'},
+ {"fields-terminated-by", required_argument, 0, (int) OPT_FTB},
+ {"fields-enclosed-by", required_argument, 0, (int) OPT_ENC},
+ {"fields-optionally-enclosed-by", required_argument, 0, (int) OPT_O_ENC},
+ {"fields-escaped-by", required_argument, 0, (int) OPT_ESC},
+ {"first-slave", no_argument, 0, 'x'},
+ {"flush-logs", no_argument, 0, 'F'},
+ {"force", no_argument, 0, 'f'},
+ {"help", no_argument, 0, '?'},
+ {"host", required_argument, 0, 'h'},
+ {"lines-terminated-by", required_argument, 0, (int) OPT_LTB},
+ {"lock-tables", no_argument, 0, 'l'},
+ {"no-create-db", no_argument, 0, 'n'},
+ {"no-create-info", no_argument, 0, 't'},
+ {"no-data", no_argument, 0, 'd'},
+ {"opt", no_argument, 0, OPT_OPTIMIZE},
+ {"password", optional_argument, 0, 'p'},
+#ifdef __WIN__
+ {"pipe", no_argument, 0, 'W'},
+#endif
+ {"port", required_argument, 0, 'P'},
+ {"quick", no_argument, 0, 'q'},
+ {"quote-names", no_argument, 0, 'Q'},
+ {"set-variable", required_argument, 0, 'O'},
+ {"socket", required_argument, 0, 'S'},
+#include "sslopt-longopts.h"
+ {"tab", required_argument, 0, 'T'},
+ {"tables", no_argument, 0, OPT_TABLES},
+#ifndef DONT_ALLOW_USER_CHANGE
+ {"user", required_argument, 0, 'u'},
+#endif
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"where", required_argument, 0, 'w'},
+ {0, 0, 0, 0}
+};
+
+static const char *load_default_groups[]= { "mysqldump","client",0 };
+
+CHANGEABLE_VAR changeable_vars[] = {
+ { "max_allowed_packet", (long*) &max_allowed_packet,24*1024*1024,4096,
+ 24*1024L*1024L,MALLOC_OVERHEAD,1024},
+ { "net_buffer_length", (long*) &net_buffer_length,1024*1024L-1025,4096,
+ 24*1024L*1024L,MALLOC_OVERHEAD,1024},
+ { 0, 0, 0, 0, 0, 0, 0}
+};
+
+static void safe_exit(int error);
+static void write_heder(FILE *sql_file, char *db_name);
+static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row,
+ const char *prefix,const char *name,
+ int string_value);
+static int dump_selected_tables(char *db, char **table_names, int tables);
+static int dump_all_tables_in_db(char *db);
+static int init_dumping(char *);
+static int dump_databases(char **);
+static int dump_all_databases();
+static char *quote_name(char *name, char *buff);
+
+static void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION,
+ MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+} /* print_version */
+
+
+static void usage(void)
+{
+ uint i;
+ print_version();
+ puts("By Igor Romanenko, Monty, Jani & Sinisa");
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
+ puts("Dumping definition and data mysql database or table");
+ printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
+ printf("OR %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n",
+ my_progname);
+ printf("OR %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname);
+ printf("\n\
+ -A, --all-databases Dump all the databases. This will be same as\n\
+ --databases with all databases selected.\n\
+ -a, --all Include all MySQL specific create options.\n\
+ -#, --debug=... Output debug log. Often this is 'd:t:o,filename`.\n\
+ --character-sets-dir=...\n\
+ Directory where character sets are\n\
+ -?, --help Display this help message and exit.\n\
+ -B, --databases To dump several databases. Note the difference in\n\
+ usage; In this case no tables are given. All name\n\
+ arguments are regarded as databasenames.\n\
+ 'USE db_name;' will be included in the output\n\
+ -c, --complete-insert Use complete insert statements.\n\
+ -C, --compress Use compression in server/client protocol.\n\
+ --default-character-set=...\n\
+ Set the default character set\n\
+ -e, --extended-insert Allows utilization of the new, much faster\n\
+ INSERT syntax.\n\
+ --add-drop-table Add a 'drop table' before each create.\n\
+ --add-locks Add locks around insert statements.\n\
+ --allow-keywords Allow creation of column names that are keywords.\n\
+ --delayed-insert Insert rows with INSERT DELAYED.\n\
+ -F, --flush-logs Flush logs file in server before starting dump.\n\
+ -f, --force Continue even if we get an sql-error.\n\
+ -h, --host=... Connect to host.\n");
+puts("\
+ -l, --lock-tables Lock all tables for read.\n\
+ -n, --no-create-db 'CREATE DATABASE /*!32312 IF NOT EXISTS*/ db_name;'\n\
+ will not be put in the output. The above line will\n\
+ be added otherwise, if --databases or\n\
+ --all-databases option was given.\n\
+ -t, --no-create-info Don't write table creation info.\n\
+ -d, --no-data No row information.\n\
+ -O, --set-variable var=option\n\
+ give a variable a value. --help lists variables\n\
+ --opt Same as --add-drop-table --add-locks --all\n\
+ --extended-insert --quick --lock-tables\n\
+ -p, --password[=...] Password to use when connecting to server.\n\
+ If password is not given it's solicited on the tty.\n");
+#ifdef __WIN__
+ puts("-W, --pipe Use named pipes to connect to server");
+#endif
+ printf("\
+ -P, --port=... Port number to use for connection.\n\
+ -q, --quick Don't buffer query, dump directly to stdout.\n\
+ -Q, --quote-names Quote table and column names with `\n\
+ -S, --socket=... Socket file to use for connection.\n\
+ --tables Overrides option --databases (-B).\n");
+#include "sslopt-usage.h"
+ printf("\
+ -T, --tab=... Creates tab separated textfile for each table to\n\
+ given path. (creates .sql and .txt files).\n\
+ NOTE: This only works if mysqldump is run on\n\
+ the same machine as the mysqld daemon.\n");
+#ifndef DONT_ALLOW_USER_CHANGE
+ printf("\
+ -u, --user=# User for login if not current user.\n");
+#endif
+ printf("\
+ -v, --verbose Print info about the various stages.\n\
+ -V, --version Output version information and exit.\n\
+ -w, --where= dump only selected records; QUOTES mandatory!\n\
+ EXAMPLES: \"--where=user=\'jimf\'\" \"-wuserid>1\" \"-wuserid<1\"\n\
+ Use -T (--tab=...) with --fields-...\n\
+ --fields-terminated-by=...\n\
+ Fields in the textfile are terminated by ...\n\
+ --fields-enclosed-by=...\n\
+ Fields in the importfile are enclosed by ...\n\
+ --fields-optionally-enclosed-by=...\n\
+ Fields in the i.file are opt. enclosed by ...\n\
+ --fields-escaped-by=...\n\
+ Fields in the i.file are escaped by ...\n\
+ --lines-terminated-by=...\n\
+ Lines in the i.file are terminated by ...\n\
+");
+ print_defaults("my",load_default_groups);
+
+ printf("\nPossible variables for option --set-variable (-O) are:\n");
+ for (i=0 ; changeable_vars[i].name ; i++)
+ printf("%-20s current value: %lu\n",
+ changeable_vars[i].name,
+ (ulong) *changeable_vars[i].varptr);
+} /* usage */
+
+
+static void write_heder(FILE *sql_file, char *db_name)
+{
+ fprintf(sql_file, "# MySQL dump %s\n#\n", DUMP_VERSION);
+ fprintf(sql_file, "# Host: %s Database: %s\n",
+ current_host ? current_host : "localhost", db_name ? db_name : "");
+ fputs("#--------------------------------------------------------\n",
+ sql_file);
+ fprintf(sql_file, "# Server version\t%s\n",
+ mysql_get_server_info(&mysql_connection));
+ return;
+} /* write_heder */
+
+
+static int get_options(int *argc,char ***argv)
+{
+ int c,option_index;
+ my_bool tty_password=0;
+
+ load_defaults("my",load_default_groups,argc,argv);
+ set_all_changeable_vars(changeable_vars);
+ while ((c=getopt_long(*argc,*argv,"#::p::h:u:O:P:S:T:EBaAcCdefFlnqtvVw:?Ix",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'a':
+ create_options=1;
+ break;
+ case 'e':
+ extended_insert=1;
+ break;
+ case 'A':
+ opt_alldbs=1;
+ break;
+ case OPT_DEFAULT_CHARSET:
+ default_charset= optarg;
+ break;
+ case OPT_CHARSETS_DIR:
+ charsets_dir= optarg;
+ break;
+ case 'f':
+ ignore_errors=1;
+ break;
+ case 'F':
+ flush_logs=1;
+ break;
+ case 'h':
+ my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
+ current_host=my_strdup(optarg,MYF(MY_WME));
+ break;
+ case 'n':
+ opt_create_db = 1;
+ break;
+#ifndef DONT_ALLOW_USER_CHANGE
+ case 'u':
+ current_user=optarg;
+ break;
+#endif
+ case 'O':
+ if (set_changeable_var(optarg, changeable_vars))
+ {
+ usage();
+ return(1);
+ }
+ break;
+ case 'p':
+ if (optarg)
+ {
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ password=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ }
+ else
+ tty_password=1;
+ break;
+ case 'P':
+ opt_mysql_port= (unsigned int) atoi(optarg);
+ break;
+ case 'S':
+ opt_mysql_unix_port= optarg;
+ break;
+ case 'W':
+#ifdef __WIN__
+ opt_mysql_unix_port=MYSQL_NAMEDPIPE;
+#endif
+ break;
+ case 'T':
+ path= optarg;
+ break;
+ case 'B':
+ opt_databases = 1;
+ break;
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o");
+ break;
+ case 'c': cFlag=1; break;
+ case 'C':
+ opt_compress=1;
+ break;
+ case 'd': dFlag=1; break;
+ case 'l': lock_tables=1; break;
+ case 'q': quick=1; break;
+ case 'Q': opt_quoted=1; break;
+ case 't': tFlag=1; break;
+ case 'v': verbose=1; break;
+ case 'V': print_version(); exit(0);
+ case 'w':
+ where=optarg;
+ break;
+ case 'x':
+ opt_first_slave=1;
+ break;
+ default:
+ fprintf(stderr,"%s: Illegal option character '%c'\n",my_progname,opterr);
+ /* Fall throught */
+ case 'I':
+ case '?':
+ usage();
+ exit(0);
+ case (int) OPT_FTB:
+ fields_terminated= optarg;
+ break;
+ case (int) OPT_LTB:
+ lines_terminated= optarg;
+ break;
+ case (int) OPT_ENC:
+ enclosed= optarg;
+ break;
+ case (int) OPT_O_ENC:
+ opt_enclosed= optarg;
+ break;
+ case (int) OPT_ESC:
+ escaped= optarg;
+ break;
+ case (int) OPT_DROP:
+ opt_drop=1;
+ break;
+ case (int) OPT_KEYWORDS:
+ opt_keywords=1;
+ break;
+ case (int) OPT_LOCKS:
+ opt_lock=1;
+ break;
+ case (int) OPT_OPTIMIZE:
+ extended_insert=opt_drop=opt_lock=lock_tables=quick=create_options=1;
+ break;
+ case (int) OPT_DELAYED:
+ opt_delayed=1;
+ break;
+ case (int) OPT_TABLES:
+ opt_databases=0;
+ break;
+#include "sslopt-case.h"
+ }
+ }
+ if (opt_delayed)
+ opt_lock=0; /* Can't have lock with delayed */
+ if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
+ fields_terminated))
+ {
+ fprintf(stderr, "%s: You must use option --tab with --fields-...\n", my_progname);
+ return(1);
+ }
+
+ if (enclosed && opt_enclosed)
+ {
+ fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname);
+ return(1);
+ }
+ if (replace && ignore)
+ {
+ fprintf(stderr, "%s: You can't use --ignore (-i) and --replace (-r) at the same time.\n",my_progname);
+ return(1);
+ }
+ if ((opt_databases || opt_alldbs) && path)
+ {
+ fprintf(stderr,
+ "%s: --databases or --all-databases can't be used with --tab.\n",
+ my_progname);
+ return(1);
+ }
+ if (default_charset)
+ {
+ if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
+ exit(1);
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs))
+ {
+ usage();
+ return 1;
+ }
+ if (tty_password)
+ password=get_tty_password(NullS);
+ return(0);
+} /* get_options */
+
+
+/*
+** DBerror -- prints mysql error message and exits the program.
+*/
+static void DBerror(MYSQL *mysql, const char *when)
+{
+ DBUG_ENTER("DBerror");
+ my_printf_error(0,"Got error: %d: %s %s", MYF(0),
+ mysql_errno(mysql), mysql_error(mysql), when);
+ safe_exit(EX_MYSQLERR);
+ DBUG_VOID_RETURN;
+} /* DBerror */
+
+
+static void safe_exit(int error)
+{
+ if (!first_error)
+ first_error= error;
+ if (ignore_errors)
+ return;
+ if (sock)
+ mysql_close(sock);
+ exit(error);
+}
+/* safe_exit */
+
+
+/*
+** dbConnect -- connects to the host and selects DB.
+** Also checks whether the tablename is a valid table name.
+*/
+static int dbConnect(char *host, char *user,char *passwd)
+{
+ DBUG_ENTER("dbConnect");
+ if (verbose)
+ {
+ fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost");
+ }
+ mysql_init(&mysql_connection);
+ if (opt_compress)
+ mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS);
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath);
+#endif
+ if (!(sock= mysql_real_connect(&mysql_connection,host,user,passwd,
+ NULL,opt_mysql_port,opt_mysql_unix_port,
+ 0)))
+ {
+ DBerror(&mysql_connection, "when trying to connect");
+ return 1;
+ }
+ return 0;
+} /* dbConnect */
+
+
+/*
+** dbDisconnect -- disconnects from the host.
+*/
+static void dbDisconnect(char *host)
+{
+ if (verbose)
+ fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
+ mysql_close(sock);
+} /* dbDisconnect */
+
+
+static void unescape(FILE *file,char *pos,uint length)
+{
+ char *tmp;
+ DBUG_ENTER("unescape");
+ if (!(tmp=(char*) my_malloc(length*2+1, MYF(MY_WME))))
+ {
+ ignore_errors=0; /* Fatal error */
+ safe_exit(EX_MYSQLERR); /* Force exit */
+ }
+ mysql_real_escape_string(&mysql_connection,tmp, pos, length);
+ fputc('\'', file);
+ fputs(tmp, file);
+ fputc('\'', file);
+ my_free(tmp, MYF(MY_WME));
+ DBUG_VOID_RETURN;
+} /* unescape */
+
+
+static my_bool test_if_special_chars(const char *str)
+{
+#if MYSQL_VERSION_ID >= 32300
+ for ( ; *str ; str++)
+ if (!isvar(*str) && *str != '$')
+ return 1;
+#endif
+ return 0;
+} /* test_if_special_chars */
+
+static char *quote_name(char *name, char *buff)
+{
+ char *end;
+ if (!opt_quoted && !test_if_special_chars(name))
+ return name;
+ buff[0]=QUOTE_CHAR;
+ end=strmov(buff+1,name);
+ end[0]=QUOTE_CHAR;
+ end[1]=0;
+ return buff;
+} /* quote_name */
+
+
+/*
+** getStructure -- retrievs database structure, prints out corresponding
+** CREATE statement and fills out insert_pat.
+** Return values: number of fields in table, 0 if error
+*/
+static uint getTableStructure(char *table, char* db)
+{
+ MYSQL_RES *tableRes;
+ MYSQL_ROW row;
+ my_bool init=0;
+ uint numFields;
+ char *strpos, *table_name;
+ const char *delayed;
+ char name_buff[NAME_LEN+3],table_buff[NAME_LEN+3];
+ FILE *sql_file = stdout;
+ DBUG_ENTER("getTableStructure");
+
+ delayed= opt_delayed ? " DELAYED " : "";
+
+ if (verbose)
+ fprintf(stderr, "# Retrieving table structure for table %s...\n", table);
+
+ table_name=quote_name(table,table_buff);
+ sprintf(insert_pat,"show fields from %s",table_name);
+ if (mysql_query(sock,insert_pat) || !(tableRes=mysql_store_result(sock)))
+ {
+ fprintf(stderr, "%s: Can't get info about table: '%s'\nerror: %s\n",
+ my_progname, table, mysql_error(sock));
+ if (sql_file != stdout)
+ my_fclose(sql_file, MYF(MY_WME));
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
+ }
+
+ /* Make an sql-file, if path was given iow. option -T was given */
+ if (!tFlag)
+ {
+ if (path)
+ {
+ char filename[FN_REFLEN], tmp_path[FN_REFLEN];
+ strmov(tmp_path,path);
+ convert_dirname(tmp_path);
+ sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
+ O_WRONLY, MYF(MY_WME));
+ if (!sql_file) /* If file couldn't be opened */
+ {
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
+ }
+ write_heder(sql_file, db);
+ }
+ fprintf(sql_file, "\n#\n# Table structure for table '%s'\n#\n\n", table);
+ if (opt_drop)
+ fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",table_name);
+ fprintf(sql_file, "CREATE TABLE %s (\n", table_name);
+ }
+ if (cFlag)
+ sprintf(insert_pat, "INSERT %sINTO %s (", delayed, table_name);
+ else
+ {
+ sprintf(insert_pat, "INSERT %sINTO %s VALUES ", delayed, table_name);
+ if (!extended_insert)
+ strcat(insert_pat,"(");
+ }
+
+ strpos=strend(insert_pat);
+ while ((row=mysql_fetch_row(tableRes)))
+ {
+ ulong *lengths=mysql_fetch_lengths(tableRes);
+ if (init)
+ {
+ if (!tFlag)
+ fputs(",\n",sql_file);
+ if (cFlag)
+ strpos=strmov(strpos,", ");
+ }
+ init=1;
+ if (cFlag)
+ strpos=strmov(strpos,quote_name(row[SHOW_FIELDNAME],name_buff));
+ if (!tFlag)
+ {
+ if (opt_keywords)
+ fprintf(sql_file, " %s.%s %s", table_name,
+ quote_name(row[SHOW_FIELDNAME],name_buff), row[SHOW_TYPE]);
+ else
+ fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME],name_buff),
+ row[SHOW_TYPE]);
+ if (row[SHOW_DEFAULT])
+ {
+ fputs(" DEFAULT ", sql_file);
+ unescape(sql_file,row[SHOW_DEFAULT],lengths[SHOW_DEFAULT]);
+ }
+ if (!row[SHOW_NULL][0])
+ fputs(" NOT NULL", sql_file);
+ if (row[SHOW_EXTRA][0])
+ fprintf(sql_file, " %s",row[SHOW_EXTRA]);
+ }
+ }
+ numFields = (uint) mysql_num_rows(tableRes);
+ mysql_free_result(tableRes);
+ if (!tFlag)
+ {
+ char buff[20+FN_REFLEN];
+ uint keynr,primary_key;
+ sprintf(buff,"show keys from %s",table_name);
+ if (mysql_query(sock, buff))
+ {
+ fprintf(stderr, "%s: Can't get keys for table '%s' (%s)\n",
+ my_progname, table, mysql_error(sock));
+ if (sql_file != stdout)
+ my_fclose(sql_file, MYF(MY_WME));
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
+ }
+
+ tableRes=mysql_store_result(sock);
+ /* Find first which key is primary key */
+ keynr=0;
+ primary_key=INT_MAX;
+ while ((row=mysql_fetch_row(tableRes)))
+ {
+ if (atoi(row[3]) == 1)
+ {
+ keynr++;
+#ifdef FORCE_PRIMARY_KEY
+ if (atoi(row[1]) == 0 && primary_key == INT_MAX)
+ primary_key=keynr;
+#endif
+ if (!strcmp(row[2],"PRIMARY"))
+ {
+ primary_key=keynr;
+ break;
+ }
+ }
+ }
+ mysql_data_seek(tableRes,0);
+ keynr=0;
+ while ((row=mysql_fetch_row(tableRes)))
+ {
+ if (atoi(row[3]) == 1)
+ {
+ if (keynr++)
+ putc(')', sql_file);
+ if (atoi(row[1])) /* Test if duplicate key */
+ /* Duplicate allowed */
+ fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff));
+ else if (keynr == primary_key)
+ fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
+ else
+ fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff));
+ }
+ else
+ putc(',', sql_file);
+ fputs(quote_name(row[4],name_buff), sql_file);
+ if (row[7])
+ fprintf(sql_file, "(%s)",row[7]); /* Sub key */
+ }
+ if (keynr)
+ putc(')', sql_file);
+ fputs("\n)",sql_file);
+
+ /* Get MySQL specific create options */
+ if (create_options)
+ {
+ sprintf(buff,"show table status like '%s'",table);
+ if (mysql_query(sock, buff))
+ {
+ if (mysql_errno(sock) != ER_PARSE_ERROR)
+ { /* If old MySQL version */
+ if (verbose)
+ fprintf(stderr,
+ "# Warning: Couldn't get status information for table '%s' (%s)\n",
+ table,mysql_error(sock));
+ }
+ }
+ else if (!(tableRes=mysql_store_result(sock)) ||
+ !(row=mysql_fetch_row(tableRes)))
+ {
+ fprintf(stderr,
+ "Error: Couldn't read status information for table '%s' (%s)\n",
+ table,mysql_error(sock));
+ }
+ else
+ {
+ fputs("/*!",sql_file);
+ print_value(sql_file,tableRes,row,"type=","Type",0);
+ print_value(sql_file,tableRes,row,"","Create_options",0);
+ print_value(sql_file,tableRes,row,"comment=","Comment",1);
+ fputs(" */",sql_file);
+ }
+ mysql_free_result(tableRes); /* Is always safe to free */
+ }
+ fputs(";\n", sql_file);
+ }
+ if (cFlag)
+ {
+ strpos=strmov(strpos,") VALUES ");
+ if (!extended_insert)
+ strpos=strmov(strpos,"(");
+ }
+ DBUG_RETURN(numFields);
+} /* getTableStructure */
+
+
+static char *add_load_option(char *ptr,const char *object,
+ const char *statement)
+{
+ if (object)
+ {
+ ptr= strxmov(ptr," ",statement," '",NullS);
+ ptr= field_escape(ptr,object,strlen(object));
+ *ptr++= '\'';
+ }
+ return ptr;
+} /* add_load_option */
+
+
+/*
+** Allow the user to specify field terminator strings like:
+** "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
+** This is done by doubleing ' and add a end -\ if needed to avoid
+** syntax errors from the SQL parser.
+*/
+
+static char *field_escape(char *to,const char *from,uint length)
+{
+ const char *end;
+ uint end_backslashes=0;
+
+ for (end= from+length; from != end; from++)
+ {
+ *to++= *from;
+ if (*from == '\\')
+ end_backslashes^=1; /* find odd number of backslashes */
+ else
+ {
+ if (*from == '\'' && !end_backslashes)
+ *to++= *from; /* We want a duplicate of "'" for MySQL */
+ end_backslashes=0;
+ }
+ }
+ /* Add missing backslashes if user has specified odd number of backs.*/
+ if (end_backslashes)
+ *to++= '\\';
+ return to;
+} /* field_escape */
+
+
+/*
+** dumpTable saves database contents as a series of INSERT statements.
+*/
+static void dumpTable(uint numFields, char *table)
+{
+ char query[1024], *end, buff[256],table_buff[NAME_LEN+3];
+ MYSQL_RES *res;
+ MYSQL_FIELD *field;
+ MYSQL_ROW row;
+ ulong rownr, row_break, total_length, init_length;
+
+ if (verbose)
+ fprintf(stderr, "# Sending SELECT query...\n");
+ if (path)
+ {
+ char filename[FN_REFLEN], tmp_path[FN_REFLEN];
+ strmov(tmp_path, path);
+ convert_dirname(tmp_path);
+ my_load_path(tmp_path, tmp_path, NULL);
+ fn_format(filename, table, tmp_path, ".txt", 4);
+ my_delete(filename, MYF(0)); /* 'INTO OUTFILE' doesn't work, if
+ filename wasn't deleted */
+ to_unix_path(filename);
+ sprintf(query, "SELECT * INTO OUTFILE '%s'", filename);
+ end= strend(query);
+ if (replace)
+ end= strmov(end, " REPLACE");
+ if (ignore)
+ end= strmov(end, " IGNORE");
+
+ if (fields_terminated || enclosed || opt_enclosed || escaped)
+ end= strmov(end, " FIELDS");
+ end= add_load_option(end, fields_terminated, " TERMINATED BY");
+ end= add_load_option(end, enclosed, " ENCLOSED BY");
+ end= add_load_option(end, opt_enclosed, " OPTIONALLY ENCLOSED BY");
+ end= add_load_option(end, escaped, " ESCAPED BY");
+ end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
+ *end= '\0';
+
+ sprintf(buff," FROM %s",table);
+ end= strmov(end,buff);
+ if (where)
+ end= strxmov(end, " WHERE ",where,NullS);
+ if (mysql_query(sock, query))
+ {
+ DBerror(sock, "when executing 'SELECT INTO OUTFILE'");
+ return;
+ }
+ }
+ else
+ {
+ printf("\n#\n# Dumping data for table '%s'\n", table);
+ sprintf(query, "SELECT * FROM %s", quote_name(table,table_buff));
+ if (where)
+ {
+ printf("# WHERE: %s\n",where);
+ strxmov(strend(query), " WHERE ",where,NullS);
+ }
+ puts("#\n");
+
+ if (mysql_query(sock, query))
+ {
+ DBerror(sock, "when retrieving data from server");
+ return;
+ }
+ if (quick)
+ res=mysql_use_result(sock);
+ else
+ res=mysql_store_result(sock);
+ if (!res)
+ {
+ DBerror(sock, "when retrieving data from server");
+ return;
+ }
+ if (verbose)
+ fprintf(stderr, "# Retrieving rows...\n");
+ if (mysql_num_fields(res) != numFields)
+ {
+ fprintf(stderr,"%s: Error in field count for table: '%s' ! Aborting.\n",
+ my_progname,table);
+ safe_exit(EX_CONSCHECK);
+ return;
+ }
+
+ if (opt_lock)
+ printf("LOCK TABLES %s WRITE;\n", quote_name(table,table_buff));
+
+ total_length=net_buffer_length; /* Force row break */
+ row_break=0;
+ rownr=0;
+ init_length=strlen(insert_pat)+4;
+
+ while ((row=mysql_fetch_row(res)))
+ {
+ uint i;
+ ulong *lengths=mysql_fetch_lengths(res);
+ rownr++;
+ if (!extended_insert)
+ fputs(insert_pat,stdout);
+ mysql_field_seek(res,0);
+
+ for (i = 0; i < mysql_num_fields(res); i++)
+ {
+ if (!(field = mysql_fetch_field(res)))
+ {
+ sprintf(query,"%s: Not enough fields from table '%s'! Aborting.\n",
+ my_progname,table);
+ fputs(query,stderr);
+ safe_exit(EX_CONSCHECK);
+ return;
+ }
+ if (extended_insert)
+ {
+ ulong length = lengths[i];
+ if (i == 0)
+ dynstr_set(&extended_row,"(");
+ else
+ dynstr_append(&extended_row,",");
+
+ if (row[i])
+ {
+ if (length)
+ {
+ if (!IS_NUM(field->type))
+ {
+ if (dynstr_realloc(&extended_row,length * 2+2))
+ {
+ fputs("Aborting dump (out of memory)",stderr);
+ safe_exit(EX_EOM);
+ }
+ dynstr_append(&extended_row,"\'");
+ extended_row.length +=
+ mysql_real_escape_string(&mysql_connection,
+ &extended_row.str[extended_row.length],row[i],length);
+ extended_row.str[extended_row.length]='\0';
+ dynstr_append(&extended_row,"\'");
+ }
+ else
+ dynstr_append(&extended_row,row[i]);
+ }
+ else
+ dynstr_append(&extended_row,"\'\'");
+ }
+ else if (dynstr_append(&extended_row,"NULL"))
+ {
+ fputs("Aborting dump (out of memory)",stderr);
+ safe_exit(EX_EOM);
+ }
+ }
+ else
+ {
+ if (i)
+ putchar(',');
+ if (row[i])
+ {
+ if (!IS_NUM(field->type))
+ unescape(stdout, row[i], lengths[i]);
+ else
+ fputs(row[i],stdout);
+ }
+ else
+ {
+ fputs("NULL",stdout);
+ }
+ }
+ }
+
+ if (extended_insert)
+ {
+ ulong row_length;
+ dynstr_append(&extended_row,")");
+ row_length = 2 + extended_row.length;
+ if (total_length + row_length < net_buffer_length)
+ {
+ total_length += row_length;
+ putchar(','); /* Always row break */
+ fputs(extended_row.str,stdout);
+ }
+ else
+ {
+ if (row_break)
+ puts(";");
+ row_break=1; /* This is first row */
+ fputs(insert_pat,stdout);
+ fputs(extended_row.str,stdout);
+ total_length = row_length+init_length;
+ }
+ }
+ else
+ {
+ puts(");");
+ }
+ }
+ if (extended_insert && row_break)
+ puts(";"); /* If not empty table */
+ fflush(stdout);
+ if (mysql_errno(sock))
+ {
+ sprintf(query,"%s: Error %d: %s when dumping table '%s' at row: %ld\n",
+ my_progname,
+ mysql_errno(sock),
+ mysql_error(sock),
+ table,
+ rownr);
+ fputs(query,stderr);
+ safe_exit(EX_CONSCHECK);
+ return;
+ }
+ if (opt_lock)
+ puts("UNLOCK TABLES;");
+ mysql_free_result(res);
+ }
+} /* dumpTable */
+
+
+static char *getTableName(int reset)
+{
+ static MYSQL_RES *res = NULL;
+ MYSQL_ROW row;
+
+ if (!res)
+ {
+ if (!(res = mysql_list_tables(sock,NullS)))
+ return(NULL);
+ }
+ if ((row = mysql_fetch_row(res)))
+ return((char*) row[0]);
+
+ if (reset)
+ mysql_data_seek(res,0); /* We want to read again */
+ else
+ {
+ mysql_free_result(res);
+ res = NULL;
+ }
+ return(NULL);
+} /* getTableName */
+
+
+static int dump_all_databases()
+{
+ MYSQL_ROW row;
+ MYSQL_RES *tableres;
+ int result=0;
+
+ if (mysql_query(sock, "SHOW DATABASES") ||
+ !(tableres = mysql_store_result(sock)))
+ {
+ my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
+ MYF(0), mysql_error(sock));
+ return 1;
+ }
+ while ((row = mysql_fetch_row(tableres)))
+ {
+ if (dump_all_tables_in_db(row[0]))
+ result=1;
+ }
+ return result;
+}
+/* dump_all_databases */
+
+
+static int dump_databases(char **db_names)
+{
+ int result=0;
+ for ( ; *db_names ; db_names++)
+ {
+ if (dump_all_tables_in_db(*db_names))
+ result=1;
+ }
+ return result;
+} /* dump_databases */
+
+
+static int init_dumping(char *database)
+{
+ if (mysql_select_db(sock, database))
+ {
+ DBerror(sock, "when selecting the database");
+ return 1; /* If --force */
+ }
+ if (!path)
+ {
+ if (opt_databases || opt_alldbs)
+ {
+ printf("\n#\n# Current Database: %s\n#\n", database);
+ if (!opt_create_db)
+ printf("\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", database);
+ printf("\nUSE %s;\n", database);
+ }
+ }
+ if (extended_insert)
+ if (init_dynamic_string(&extended_row, "", 1024, 1024))
+ exit(EX_EOM);
+ return 0;
+} /* init_dumping */
+
+
+static int dump_all_tables_in_db(char *database)
+{
+ char *table;
+ uint numrows;
+
+ if (init_dumping(database))
+ return 1;
+ if (lock_tables)
+ {
+ DYNAMIC_STRING query;
+ init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
+ for (numrows=0 ; (table = getTableName(1)) ; numrows++)
+ {
+ dynstr_append(&query, table);
+ dynstr_append(&query, " READ /*!32311 LOCAL */,");
+ }
+ if (numrows && mysql_real_query(sock, query.str, query.length-1))
+ DBerror(sock, "when using LOCK TABLES");
+ /* We shall continue here, if --force was given */
+ dynstr_free(&query);
+ }
+ if (flush_logs)
+ {
+ if (mysql_refresh(sock, REFRESH_LOG))
+ DBerror(sock, "when doing refresh");
+ /* We shall continue here, if --force was given */
+ }
+ while ((table = getTableName(0)))
+ {
+ numrows = getTableStructure(table, database);
+ if (!dFlag && numrows > 0)
+ dumpTable(numrows,table);
+ }
+ if (lock_tables)
+ mysql_query(sock,"UNLOCK_TABLES");
+ return 0;
+} /* dump_all_tables_in_db */
+
+
+
+static int dump_selected_tables(char *db, char **table_names, int tables)
+{
+ uint numrows;
+
+ if (init_dumping(db))
+ return 1;
+ if (lock_tables)
+ {
+ DYNAMIC_STRING query;
+ int i;
+
+ init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
+ for (i=0 ; i < tables ; i++)
+ {
+ dynstr_append(&query, table_names[i]);
+ dynstr_append(&query, " READ /*!32311 LOCAL */,");
+ }
+ if (mysql_real_query(sock, query.str, query.length-1))
+ DBerror(sock, "when doing LOCK TABLES");
+ /* We shall countinue here, if --force was given */
+ dynstr_free(&query);
+ }
+ if (flush_logs)
+ {
+ if (mysql_refresh(sock, REFRESH_LOG))
+ DBerror(sock, "when doing refresh");
+ /* We shall countinue here, if --force was given */
+ }
+ for (; tables > 0 ; tables-- , table_names++)
+ {
+ numrows = getTableStructure(*table_names, db);
+ if (!dFlag && numrows > 0)
+ dumpTable(numrows, *table_names);
+ }
+ if (lock_tables)
+ mysql_query(sock,"UNLOCK_TABLES");
+ return 0;
+} /* dump_selected_tables */
+
+
+/* Print a value with a prefix on file */
+static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row,
+ const char *prefix, const char *name,
+ int string_value)
+{
+ MYSQL_FIELD *field;
+ mysql_field_seek(result, 0);
+
+ for ( ; (field = mysql_fetch_field(result)) ; row++)
+ {
+ if (!strcmp(field->name,name))
+ {
+ if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */
+ {
+ fputc(' ',file);
+ fputs(prefix, file);
+ if (string_value)
+ unescape(file,row[0],strlen(row[0]));
+ else
+ fputs(row[0], file);
+ return;
+ }
+ }
+ }
+ return; /* This shouldn't happen */
+} /* print_value */
+
+
+int main(int argc, char **argv)
+{
+ MY_INIT(argv[0]);
+ /*
+ ** Check out the args
+ */
+ if (get_options(&argc, &argv))
+ {
+ my_end(0);
+ exit(EX_USAGE);
+ }
+ if (dbConnect(current_host, current_user, password))
+ exit(EX_MYSQLERR);
+ if (!path)
+ write_heder(stdout, *argv);
+
+ if (opt_first_slave)
+ {
+ lock_tables=0; /* No other locks needed */
+ if (mysql_query(sock, "FLUSH TABLES WITH READ LOCK"))
+ {
+ my_printf_error(0, "Error: Couldn't execute 'FLUSH TABLES WITH READ LOCK': %s",
+ MYF(0), mysql_error(sock));
+ my_end(0);
+ return(first_error);
+ }
+ }
+ if (opt_alldbs)
+ dump_all_databases();
+ /* Only one database and selected table(s) */
+ else if (argc > 1 && !opt_databases)
+ dump_selected_tables(*argv, (argv + 1), (argc - 1));
+ /* One or more databases, all tables */
+ else
+ dump_databases(argv);
+
+ if (opt_first_slave)
+ {
+ if (mysql_query(sock, "FLUSH MASTER"))
+ {
+ my_printf_error(0, "Error: Couldn't execute 'FLUSH MASTER': %s",
+ MYF(0), mysql_error(sock));
+ }
+ if (mysql_query(sock, "UNLOCK TABLES"))
+ {
+ my_printf_error(0, "Error: Couldn't execute 'UNLOCK TABLES': %s",
+ MYF(0), mysql_error(sock));
+ }
+ }
+ dbDisconnect(current_host);
+ puts("");
+ my_free(password, MYF(MY_ALLOW_ZERO_PTR));
+ if (extended_insert)
+ dynstr_free(&extended_row);
+ my_end(0);
+ return(first_error);
+} /* main */
diff --git a/client/mysqlimport.c b/client/mysqlimport.c
new file mode 100644
index 00000000000..28cacaa58dc
--- /dev/null
+++ b/client/mysqlimport.c
@@ -0,0 +1,521 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+** mysqlimport.c - Imports all given files
+** into a table(s).
+**
+** *************************
+** * *
+** * AUTHOR: Monty & Jani *
+** * DATE: June 24, 1997 *
+** * *
+** *************************
+*/
+#define IMPORT_VERSION "2.3"
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+#include "mysql_version.h"
+#include <getopt.h>
+
+
+static void db_error_with_table(MYSQL *mysql, char *table);
+static void db_error(MYSQL *mysql);
+static char *field_escape(char *to,const char *from,uint length);
+static char *add_load_option(char *ptr,const char *object,
+ const char *statement);
+
+static my_bool verbose=0,lock_tables=0,ignore_errors=0,delete=0,
+ replace=0,silent=0,ignore=0,opt_compress=0,opt_local_file=0;
+
+static MYSQL mysql_connection;
+static char *password=0, *current_user=0,
+ *current_host=0, *current_db=0, *fields_terminated=0,
+ *lines_terminated=0, *enclosed=0, *opt_enclosed=0,
+ *escaped=0, opt_low_priority=0, *opt_columns=0;
+static uint opt_mysql_port=0;
+static my_string opt_mysql_unix_port=0;
+#include "sslopt-vars.h"
+
+enum options {OPT_FTB=256, OPT_LTB, OPT_ENC, OPT_O_ENC, OPT_ESC,
+ OPT_LOW_PRIORITY, OPT_CHARSETS_DIR};
+
+static struct option long_options[] =
+{
+ {"character-sets-dir", required_argument, 0, OPT_CHARSETS_DIR},
+ {"columns", required_argument, 0, 'c'},
+ {"compress", no_argument, 0, 'C'},
+ {"debug", optional_argument, 0, '#'},
+ {"delete", no_argument, 0, 'd'},
+ {"fields-terminated-by", required_argument, 0, (int) OPT_FTB},
+ {"fields-enclosed-by", required_argument, 0, (int) OPT_ENC},
+ {"fields-optionally-enclosed-by", required_argument, 0, (int) OPT_O_ENC},
+ {"fields-escaped-by", required_argument, 0, (int) OPT_ESC},
+ {"force", no_argument, 0, 'f'},
+ {"help", no_argument, 0, '?'},
+ {"host", required_argument, 0, 'h'},
+ {"ignore", no_argument, 0, 'i'},
+ {"lines-terminated-by", required_argument, 0, (int) OPT_LTB},
+ {"local", no_argument, 0, 'L'},
+ {"lock-tables", no_argument, 0, 'l'},
+ {"low-priority", no_argument, 0, (int) OPT_LOW_PRIORITY},
+ {"password", optional_argument, 0, 'p'},
+#ifdef __WIN__
+ {"pipe", no_argument, 0, 'W'},
+#endif
+ {"port", required_argument, 0, 'P'},
+ {"replace", no_argument, 0, 'r'},
+ {"silent", no_argument, 0, 's'},
+ {"socket", required_argument, 0, 'S'},
+#include "sslopt-longopts.h"
+#ifndef DONT_ALLOW_USER_CHANGE
+ {"user", required_argument, 0, 'u'},
+#endif
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0}
+};
+
+
+static const char *load_default_groups[]= { "mysqlimport","client",0 };
+
+static void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s (%s)\n" ,my_progname,
+ IMPORT_VERSION, MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+
+
+static void usage(void)
+{
+ print_version();
+ puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB");
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
+ printf("\
+Loads tables from text files in various formats. The base name of the\n\
+text file must be the name of the table that should be used.\n\
+If one uses sockets to connect to the MySQL server, the server will open and\n\
+read the text file directly. In other cases the client will open the text\n\
+file. The SQL command 'LOAD DATA INFILE' is used to import the rows.\n");
+
+ printf("\nUsage: %s [OPTIONS] database textfile...",my_progname);
+ printf("\n\
+ -#, --debug[=...] Output debug log. Often this is 'd:t:o,filename`\n\
+ -?, --help Displays this help and exits.\n\
+ --character-sets-dir=...\n\
+ Directory where character sets are\n\
+ -c, --columns=... Use only these columns to import the data to.\n\
+ Give the column names in a comma separated list.\n\
+ This is same as giving columns to LOAD DATA INFILE.\n\
+ -C, --compress Use compression in server/client protocol\n\
+ -d, --delete Deletes first all rows from table.\n\
+ -f, --force Continue even if we get an sql-error.\n\
+ -h, --host=... Connect to host.\n\
+ -i, --ignore If duplicate unique key was found, keep old row.\n\
+ -l, --lock-tables Lock all tables for write.\n\
+ -L, --local Read all files through the client\n\
+ --low-priority Use LOW_PRIORITY when updating the table\n\
+ -p, --password[=...] Password to use when connecting to server.\n\
+ If password is not given it's asked from the tty.\n");
+#ifdef __WIN__
+ puts("-W, --pipe Use named pipes to connect to server");
+#endif
+ printf("\
+ -P, --port=... Port number to use for connection.\n\
+ -r, --replace If duplicate unique key was found, replace old row.\n\
+ -s, --silent Be more silent.\n\
+ -S, --socket=... Socket file to use for connection.\n");
+#include "sslopt-usage.h"
+#ifndef DONT_ALLOW_USER_CHANGE
+ printf("\
+ -u, --user=# User for login if not current user.\n");
+#endif
+ printf("\
+ -v, --verbose Print info about the various stages.\n\
+ -V, --version Output version information and exit.\n\
+ --fields-terminated-by=...\n\
+ Fields in the textfile are terminated by ...\n\
+ --fields-enclosed-by=...\n\
+ Fields in the importfile are enclosed by ...\n\
+ --fields-optionally-enclosed-by=...\n\
+ Fields in the i.file are opt. enclosed by ...\n\
+ --fields-escaped-by=...\n\
+ Fields in the i.file are escaped by ...\n\
+ --lines-terminated-by=...\n\
+ Lines in the i.file are terminated by ...\n\
+");
+ print_defaults("my",load_default_groups);
+}
+
+static int get_options(int *argc, char ***argv)
+{
+ int c, option_index;
+ my_bool tty_password=0;
+
+ while ((c=getopt_long(*argc,*argv,"#::p::c:h:u:P:S:CdfilLrsvV?IW",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'c':
+ opt_columns= optarg;
+ break;
+ case 'C':
+ opt_compress=1;
+ break;
+ case OPT_CHARSETS_DIR:
+ charsets_dir= optarg;
+ break;
+ case 'd':
+ delete= 1;
+ break;
+ case 'f':
+ ignore_errors= 1;
+ break;
+ case 'h':
+ current_host= optarg;
+ break;
+ case 'i':
+ ignore= 1;
+ break;
+#ifndef DONT_ALLOW_USER_CHANGE
+ case 'u':
+ current_user= optarg;
+ break;
+#endif
+ case 'p':
+ if (optarg)
+ {
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ password= my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ }
+ else
+ tty_password= 1;
+ break;
+ case 'P':
+ opt_mysql_port= (unsigned int) atoi(optarg);
+ break;
+ case 'r':
+ replace= 1;
+ break;
+ case 's':
+ silent= 1;
+ break;
+ case 'S':
+ opt_mysql_unix_port= optarg;
+ break;
+#ifdef __WIN__
+ case 'W':
+ opt_mysql_unix_port=MYSQL_NAMEDPIPE;
+ opt_local_file=1;
+ break;
+#endif
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o");
+ break;
+ case 'l': lock_tables= 1; break;
+ case 'L': opt_local_file=1; break;
+ case 'v': verbose= 1; break;
+ case 'V': print_version(); exit(0);
+ case 'I':
+ case '?':
+ usage();
+ exit(0);
+ case (int) OPT_FTB:
+ fields_terminated= optarg;
+ break;
+ case (int) OPT_LTB:
+ lines_terminated= optarg;
+ break;
+ case (int) OPT_ENC:
+ enclosed= optarg;
+ break;
+ case (int) OPT_O_ENC:
+ opt_enclosed= optarg;
+ break;
+ case (int) OPT_ESC:
+ escaped= optarg;
+ break;
+#include "sslopt-case.h"
+ }
+ }
+ if (enclosed && opt_enclosed)
+ {
+ fprintf(stderr, "You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n");
+ return(1);
+ }
+ if (replace && ignore)
+ {
+ fprintf(stderr, "You can't use --ignore (-i) and --replace (-r) at the same time.\n");
+ return(1);
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (*argc < 2)
+ {
+ usage();
+ return 1;
+ }
+ current_db= *((*argv)++);
+ (*argc)--;
+ if (tty_password)
+ password=get_tty_password(NullS);
+ return(0);
+}
+
+
+
+static int write_to_table(char *filename, MYSQL *sock)
+{
+ char tablename[FN_REFLEN], hard_path[FN_REFLEN],
+ sql_statement[FN_REFLEN*2+256], *end;
+ my_bool local_file;
+ DBUG_ENTER("write_to_table");
+ DBUG_PRINT("enter",("filename: %s",filename));
+
+ local_file= sock->unix_socket == 0 || opt_local_file;
+
+ fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */
+ if (local_file)
+ strmov(hard_path,filename);
+ else
+ my_load_path(hard_path, filename, NULL); /* filename includes the path */
+
+ if (delete)
+ {
+ if (verbose)
+ fprintf(stdout, "Deleting the old data from table %s\n", tablename);
+ sprintf(sql_statement, "DELETE FROM %s", tablename);
+ if (mysql_query(sock, sql_statement))
+ {
+ db_error_with_table(sock, tablename);
+ DBUG_RETURN(1);
+ }
+ }
+ to_unix_path(hard_path);
+ if (verbose)
+ {
+ if (local_file)
+ fprintf(stdout, "Loading data from LOCAL file: %s into %s\n",
+ hard_path, tablename);
+ else
+ fprintf(stdout, "Loading data from SERVER file: %s into %s\n",
+ hard_path, tablename);
+ }
+ sprintf(sql_statement, "LOAD DATA %s %s INFILE '%s'",
+ opt_low_priority ? "LOW_PRIORITY" : "",
+ local_file ? "LOCAL" : "", hard_path);
+ end= strend(sql_statement);
+ if (replace)
+ end= strmov(end, " REPLACE");
+ if (ignore)
+ end= strmov(end, " IGNORE");
+ end= strmov(strmov(end, " INTO TABLE "), tablename);
+
+ if (fields_terminated || enclosed || opt_enclosed || escaped)
+ end= strmov(end, " FIELDS");
+ end= add_load_option(end, fields_terminated, " TERMINATED BY");
+ end= add_load_option(end, enclosed, " ENCLOSED BY");
+ end= add_load_option(end, opt_enclosed,
+ " OPTIONALLY ENCLOSED BY");
+ end= add_load_option(end, escaped, " ESCAPED BY");
+ end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
+ if (opt_columns)
+ end= strmov(strmov(strmov(end, " ("), opt_columns), ")");
+ *end= '\0';
+
+ if (mysql_query(sock, sql_statement))
+ {
+ db_error_with_table(sock, tablename);
+ DBUG_RETURN(1);
+ }
+ if (!silent)
+ {
+ if (mysql_info(sock)) /* If NULL-pointer, print nothing */
+ {
+ fprintf(stdout, "%s.%s: %s\n", current_db, tablename,
+ mysql_info(sock));
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+
+static void lock_table(MYSQL *sock, int tablecount, char **raw_tablename)
+{
+ DYNAMIC_STRING query;
+ int i;
+ char tablename[FN_REFLEN];
+
+ if (verbose)
+ fprintf(stdout, "Locking tables for write\n");
+ init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
+ for (i=0 ; i < tablecount ; i++)
+ {
+ fn_format(tablename, raw_tablename[i], "", "", 1 | 2);
+ dynstr_append(&query, tablename);
+ dynstr_append(&query, " WRITE,");
+ }
+ if (mysql_real_query(sock, query.str, query.length-1))
+ db_error(sock); /* We shall countinue here, if --force was given */
+}
+
+
+
+
+static MYSQL *db_connect(char *host, char *database, char *user, char *passwd)
+{
+ MYSQL *sock;
+ if (verbose)
+ fprintf(stdout, "Connecting to %s\n", host ? host : "localhost");
+ mysql_init(&mysql_connection);
+ if (opt_compress)
+ mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS);
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath);
+#endif
+ if (!(sock= mysql_real_connect(&mysql_connection,host,user,passwd,
+ database,opt_mysql_port,opt_mysql_unix_port,
+ 0)))
+ {
+ ignore_errors=0; /* NO RETURN FROM db_error */
+ db_error(&mysql_connection);
+ }
+ if (verbose)
+ fprintf(stdout, "Selecting database %s\n", database);
+ if (mysql_select_db(sock, database))
+ {
+ ignore_errors=0;
+ db_error(&mysql_connection);
+ }
+ return sock;
+}
+
+
+
+static void db_disconnect(char *host, MYSQL *sock)
+{
+ if (verbose)
+ fprintf(stdout, "Disconnecting from %s\n", host ? host : "localhost");
+ mysql_close(sock);
+}
+
+
+
+static void safe_exit(int error, MYSQL *sock)
+{
+ if (ignore_errors)
+ return;
+ if (sock)
+ mysql_close(sock);
+ exit(error);
+}
+
+
+
+static void db_error_with_table(MYSQL *mysql, char *table)
+{
+ my_printf_error(0,"Error: %s, when using table: %s",
+ MYF(0), mysql_error(mysql), table);
+ safe_exit(1, mysql);
+}
+
+
+
+static void db_error(MYSQL *mysql)
+{
+ my_printf_error(0,"Error: %s", MYF(0), mysql_error(mysql));
+ safe_exit(1, mysql);
+}
+
+
+static char *add_load_option(char *ptr,const char *object,const char *statement)
+{
+ if (object)
+ {
+ ptr= strxmov(ptr," ",statement," '",NullS);
+ ptr= field_escape(ptr,object,strlen(object));
+ *ptr++= '\'';
+ }
+ return ptr;
+}
+
+/*
+** Allow the user to specify field terminator strings like:
+** "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
+** This is done by doubleing ' and add a end -\ if needed to avoid
+** syntax errors from the SQL parser.
+*/
+
+static char *field_escape(char *to,const char *from,uint length)
+{
+ const char *end;
+ uint end_backslashes=0;
+
+ for (end= from+length; from != end; from++)
+ {
+ *to++= *from;
+ if (*from == '\\')
+ end_backslashes^=1; /* find odd number of backslashes */
+ else
+ {
+ if (*from == '\'' && !end_backslashes)
+ *to++= *from; /* We want a dublicate of "'" for MySQL */
+ end_backslashes=0;
+ }
+ }
+ /* Add missing backslashes if user has specified odd number of backs.*/
+ if (end_backslashes)
+ *to++= '\\';
+ return to;
+}
+
+
+
+int main(int argc, char **argv)
+{
+ int exitcode=0, error=0;
+ char **argv_to_free;
+ MYSQL *sock=0;
+ MY_INIT(argv[0]);
+
+ load_defaults("my",load_default_groups,&argc,&argv);
+ /* argv is changed in the program */
+ argv_to_free= argv;
+ if (get_options(&argc, &argv))
+ return(1);
+ if (!(sock= db_connect(current_host,current_db,current_user,password)))
+ return(1); /* purecov: deadcode */
+ if (lock_tables)
+ lock_table(sock, argc, argv);
+ for (; *argv != NULL; argv++)
+ if ((error=write_to_table(*argv, sock)))
+ if (exitcode == 0)
+ exitcode = error;
+ db_disconnect(current_host, sock);
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
+ free_defaults(argv_to_free);
+ my_end(0);
+ return(exitcode);
+}
diff --git a/client/mysqlshow.c b/client/mysqlshow.c
new file mode 100644
index 00000000000..6cf7cdf9963
--- /dev/null
+++ b/client/mysqlshow.c
@@ -0,0 +1,608 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Show databases, tables or columns */
+
+#define SHOW_VERSION "8.2"
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+#include "mysql_version.h"
+#include "mysqld_error.h"
+#include <signal.h>
+#include <stdarg.h>
+#include <getopt.h>
+
+static my_string host=0,password=0,user=0;
+static my_bool opt_show_keys=0,opt_compress=0,opt_status=0;
+
+static void get_options(int *argc,char ***argv);
+static uint opt_mysql_port=0;
+static int list_dbs(MYSQL *mysql,const char *wild);
+static int list_tables(MYSQL *mysql,const char *db,const char *table);
+static int list_table_status(MYSQL *mysql,const char *db,const char *table);
+static int list_fields(MYSQL *mysql,const char *db,const char *table,
+ const char *field);
+static void print_header(const char *header,uint head_length,...);
+static void print_row(const char *header,uint head_length,...);
+static void print_trailer(uint length,...);
+static void print_res_header(MYSQL_RES *result);
+static void print_res_top(MYSQL_RES *result);
+static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur);
+
+static const char *load_default_groups[]= { "mysqlshow","client",0 };
+static my_string opt_mysql_unix_port=0;
+#include "sslopt-vars.h"
+
+int main(int argc, char **argv)
+{
+ int error;
+ char *wild;
+ MYSQL mysql;
+ MY_INIT(argv[0]);
+ load_defaults("my",load_default_groups,&argc,&argv);
+ get_options(&argc,&argv);
+
+ wild=0;
+ if (argc && strcont(argv[argc-1],"*?%_"))
+ {
+ char *pos;
+
+ wild=argv[--argc];
+ for (pos=wild ; *pos ; pos++)
+ { /* Unix wildcards to sql */
+ if (*pos == '*')
+ *pos='%';
+ else if (*pos == '?')
+ *pos='_';
+ }
+ }
+ else if (argc == 3) /* We only want one field */
+ wild=argv[--argc];
+
+ if (argc > 2)
+ {
+ fprintf(stderr,"%s: Too many arguments\n",my_progname);
+ exit(1);
+ }
+ mysql_init(&mysql);
+ if (opt_compress)
+ mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath);
+#endif
+ if (!(mysql_real_connect(&mysql,host,user,password,
+ argv[0],opt_mysql_port,opt_mysql_unix_port,
+ 0)))
+ {
+ fprintf(stderr,"%s: %s\n",my_progname,mysql_error(&mysql));
+ exit(1);
+ }
+ /* if (!(mysql_connect(&mysql,host,user,password))) */
+
+
+ switch (argc)
+ {
+ case 0: error=list_dbs(&mysql,wild); break;
+ case 1:
+ if (opt_status)
+ error=list_table_status(&mysql,argv[0],wild);
+ else
+ error=list_tables(&mysql,argv[0],wild);
+ break;
+ default:
+ if (opt_status && ! wild)
+ error=list_table_status(&mysql,argv[0],argv[1]);
+ else
+ error=list_fields(&mysql,argv[0],argv[1],wild); break;
+ }
+ mysql_close(&mysql); /* Close & free connection */
+ if (password)
+ my_free(password,MYF(0));
+ my_end(0);
+ exit(error ? 1 : 0);
+ return 0; /* No compiler warnings */
+}
+
+
+static struct option long_options[] =
+{
+ {"character-sets-dir", required_argument, 0, 'c'},
+ {"compress", no_argument, 0, 'C'},
+ {"debug", optional_argument, 0, '#'},
+ {"help", no_argument, 0, '?'},
+ {"host", required_argument, 0, 'h'},
+ {"status", no_argument, 0, 'i'},
+ {"keys", no_argument, 0, 'k'},
+ {"password", optional_argument, 0, 'p'},
+ {"port", required_argument, 0, 'P'},
+#ifdef __WIN__
+ {"pipe", no_argument, 0, 'W'},
+#endif
+ {"socket", required_argument, 0, 'S'},
+#include "sslopt-longopts.h"
+#ifndef DONT_ALLOW_USER_CHANGE
+ {"user", required_argument, 0, 'u'},
+#endif
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0}
+};
+
+
+static void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,SHOW_VERSION,
+ MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+static void usage(void)
+{
+ print_version();
+ puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB");
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
+ puts("Shows the structure of a mysql database (databases,tables and columns)\n");
+ printf("Usage: %s [OPTIONS] [database [table [column]]]\n",my_progname);
+ printf("\n\
+ -#, --debug=... output debug log. Often this is 'd:t:o,filename`\n\
+ -?, --help display this help and exit\n\
+ -c, --character-sets-dir=...\n\
+ Directory where character sets are\n\
+ -C, --compress Use compression in server/client protocol\n\
+ -h, --host=... connect to host\n\
+ -i, --status Shows a lot of extra information about each table\n\
+ -k, --keys show keys for table\n\
+ -p, --password[=...] password to use when connecting to server\n\
+ If password is not given it's asked from the tty.\n");
+#ifdef __WIN__
+ puts("-W, --pipe Use named pipes to connect to server");
+#endif
+ printf("\
+ -P --port=... Port number to use for connection\n\
+ -S --socket=... Socket file to use for connection\n");
+#include "sslopt-usage.h"
+#ifndef DONT_ALLOW_USER_CHANGE
+ printf("\
+ -u, --user=# user for login if not current user\n");
+#endif
+ printf("\
+ -V, --version output version information and exit\n");
+
+ puts("\n\
+If last argument contains a shell or SQL wildcard (*,?,% or _) then only\n\
+what\'s matched by the wildcard is shown.\n\
+If no database is given then all matching databases are shown.\n\
+If no table is given then all matching tables in database are shown\n\
+If no column is given then all matching columns and columntypes in table\n\
+are shown");
+ print_defaults("my",load_default_groups);
+}
+
+
+static void
+get_options(int *argc,char ***argv)
+{
+ int c,option_index;
+ my_bool tty_password=0;
+
+ while ((c=getopt_long(*argc,*argv,"c:h:p::u:#::P:S:Ck?VWi",long_options,
+ &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'C':
+ opt_compress=1;
+ break;
+ case 'c':
+ charsets_dir= optarg;
+ break;
+ case 'h':
+ host = optarg;
+ break;
+ case 'i':
+ opt_status=1;
+ break;
+ case 'k':
+ opt_show_keys=1;
+ break;
+ case 'p':
+ if (optarg)
+ {
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ password=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ }
+ else
+ tty_password=1;
+ break;
+#ifndef DONT_ALLOW_USER_CHANGE
+ case 'u':
+ user=optarg;
+ break;
+#endif
+ case 'P':
+ opt_mysql_port= (unsigned int) atoi(optarg);
+ break;
+ case 'S':
+ opt_mysql_unix_port= optarg;
+ break;
+ case 'W':
+#ifdef __WIN__
+ opt_mysql_unix_port=MYSQL_NAMEDPIPE;
+#endif
+ break;
+#include "sslopt-case.h"
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o");
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ break;
+ default:
+ fprintf(stderr,"Illegal option character '%c'\n",opterr);
+ /* Fall throught */
+ case '?':
+ case 'I': /* Info */
+ usage();
+ exit(0);
+ }
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (tty_password)
+ password=get_tty_password(NullS);
+ return;
+}
+
+
+static int
+list_dbs(MYSQL *mysql,const char *wild)
+{
+ const char *header;
+ uint length;
+ MYSQL_FIELD *field;
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ if (!(result=mysql_list_dbs(mysql,wild)))
+ {
+ fprintf(stderr,"%s: Cannot list databases: %s\n",my_progname,
+ mysql_error(mysql));
+ return 1;
+ }
+ if (wild)
+ printf("Wildcard: %s\n",wild);
+
+ header="Databases";
+ length=strlen(header);
+ field=mysql_fetch_field(result);
+ if (length < field->max_length)
+ length=field->max_length;
+
+ print_header(header,length,NullS);
+ while ((row = mysql_fetch_row(result)))
+ print_row(row[0],length,0);
+ print_trailer(length,0);
+ mysql_free_result(result);
+ return 0;
+}
+
+
+static int
+list_tables(MYSQL *mysql,const char *db,const char *table)
+{
+ const char *header;
+ uint head_length;
+ MYSQL_FIELD *field;
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ if (mysql_select_db(mysql,db))
+ {
+ fprintf(stderr,"%s: Cannot connect to db %s: %s\n",my_progname,db,
+ mysql_error(mysql));
+ return 1;
+ }
+ if (!(result=mysql_list_tables(mysql,table)))
+ {
+ fprintf(stderr,"%s: Cannot list tables in %s: %s\n",my_progname,db,
+ mysql_error(mysql));
+ exit(1);
+ }
+ printf("Database: %s",db);
+ if (table)
+ printf(" Wildcard: %s",table);
+ putchar('\n');
+
+ header="Tables";
+ head_length=strlen(header);
+ field=mysql_fetch_field(result);
+ if (head_length < field->max_length)
+ head_length=field->max_length;
+
+ print_header(header,head_length,NullS);
+ while ((row = mysql_fetch_row(result)))
+ print_row(row[0],head_length,0);
+ print_trailer(head_length,0);
+ mysql_free_result(result);
+ return 0;
+}
+
+static int
+list_table_status(MYSQL *mysql,const char *db,const char *wild)
+{
+ char query[1024],*end;
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ end=strxmov(query,"show table status from ",db,NullS);
+ if (wild && wild[0])
+ strxmov(end," like '",wild,"'",NullS);
+ if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
+ {
+ fprintf(stderr,"%s: Cannot get status for db: %s, table: %s: %s\n",
+ my_progname,db,wild ? wild : "",mysql_error(mysql));
+ if (mysql_errno(mysql) == ER_PARSE_ERROR)
+ fprintf(stderr,"This error probably means that your MySQL server doesn't support the\n\'show table status' command.\n");
+ return 1;
+ }
+
+ printf("Database: %s",db);
+ if (wild)
+ printf(" Wildcard: %s",wild);
+ putchar('\n');
+
+ print_res_header(result);
+ while ((row=mysql_fetch_row(result)))
+ print_res_row(result,row);
+ print_res_top(result);
+ mysql_free_result(result);
+ return 0;
+}
+
+/*
+** list fields uses field interface as an example of how to parse
+** a MYSQL FIELD
+*/
+
+static int
+list_fields(MYSQL *mysql,const char *db,const char *table,
+ const char *wild)
+{
+ char query[1024],*end;
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ if (mysql_select_db(mysql,db))
+ {
+ fprintf(stderr,"%s: Cannot connect to db: %s: %s\n",my_progname,db,
+ mysql_error(mysql));
+ return 1;
+ }
+ end=strmov(strmov(query,"show columns from "),table);
+ if (wild && wild[0])
+ strxmov(end," like '",wild,"'",NullS);
+ if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
+ {
+ fprintf(stderr,"%s: Cannot list columns in db: %s, table: %s: %s\n",
+ my_progname,db,table,mysql_error(mysql));
+ return 1;
+ }
+
+ printf("Database: %s Table: %s Rows: %lu", db,table,
+ (ulong) mysql->extra_info);
+ if (wild && wild[0])
+ printf(" Wildcard: %s",wild);
+ putchar('\n');
+
+ print_res_header(result);
+ while ((row=mysql_fetch_row(result)))
+ print_res_row(result,row);
+ print_res_top(result);
+ if (opt_show_keys)
+ {
+ end=strmov(strmov(query,"show keys from "),table);
+ if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
+ {
+ fprintf(stderr,"%s: Cannot list keys in db: %s, table: %s: %s\n",
+ my_progname,db,table,mysql_error(mysql));
+ return 1;
+ }
+ if (mysql_num_rows(result))
+ {
+ print_res_header(result);
+ while ((row=mysql_fetch_row(result)))
+ print_res_row(result,row);
+ print_res_top(result);
+ }
+ else
+ puts("Table has no keys");
+ }
+ mysql_free_result(result);
+ return 0;
+}
+
+
+/*****************************************************************************
+** General functions to print a nice ascii-table from data
+*****************************************************************************/
+
+static void
+print_header(const char *header,uint head_length,...)
+{
+ va_list args;
+ uint length,i,str_length,pre_space;
+ const char *field;
+
+ va_start(args,head_length);
+ putchar('+');
+ field=header; length=head_length;
+ for (;;)
+ {
+ for (i=0 ; i < length+2 ; i++)
+ putchar('-');
+ putchar('+');
+ if (!(field=va_arg(args,my_string)))
+ break;
+ length=va_arg(args,uint);
+ }
+ va_end(args);
+ putchar('\n');
+
+ va_start(args,head_length);
+ field=header; length=head_length;
+ putchar('|');
+ for (;;)
+ {
+ str_length=strlen(field);
+ if (str_length > length)
+ str_length=length+1;
+ pre_space=(uint) (((int) length-(int) str_length)/2)+1;
+ for (i=0 ; i < pre_space ; i++)
+ putchar(' ');
+ for (i = 0 ; i < str_length ; i++)
+ putchar(field[i]);
+ length=length+2-str_length-pre_space;
+ for (i=0 ; i < length ; i++)
+ putchar(' ');
+ putchar('|');
+ if (!(field=va_arg(args,my_string)))
+ break;
+ length=va_arg(args,uint);
+ }
+ va_end(args);
+ putchar('\n');
+
+ va_start(args,head_length);
+ putchar('+');
+ field=header; length=head_length;
+ for (;;)
+ {
+ for (i=0 ; i < length+2 ; i++)
+ putchar('-');
+ putchar('+');
+ if (!(field=va_arg(args,my_string)))
+ break;
+ length=va_arg(args,uint);
+ }
+ va_end(args);
+ putchar('\n');
+}
+
+
+static void
+print_row(const char *header,uint head_length,...)
+{
+ va_list args;
+ const char *field;
+ uint i,length,field_length;
+
+ va_start(args,head_length);
+ field=header; length=head_length;
+ for (;;)
+ {
+ putchar('|');
+ putchar(' ');
+ fputs(field,stdout);
+ field_length=strlen(field);
+ for (i=field_length ; i <= length ; i++)
+ putchar(' ');
+ if (!(field=va_arg(args,my_string)))
+ break;
+ length=va_arg(args,uint);
+ }
+ va_end(args);
+ putchar('|');
+ putchar('\n');
+}
+
+
+static void
+print_trailer(uint head_length,...)
+{
+ va_list args;
+ uint length,i;
+
+ va_start(args,head_length);
+ length=head_length;
+ putchar('+');
+ for (;;)
+ {
+ for (i=0 ; i < length+2 ; i++)
+ putchar('-');
+ putchar('+');
+ if (!(length=va_arg(args,uint)))
+ break;
+ }
+ va_end(args);
+ putchar('\n');
+}
+
+
+static void print_res_header(MYSQL_RES *result)
+{
+ MYSQL_FIELD *field;
+
+ print_res_top(result);
+ mysql_field_seek(result,0);
+ putchar('|');
+ while ((field = mysql_fetch_field(result)))
+ {
+ printf(" %-*s|",field->max_length+1,field->name);
+ }
+ putchar('\n');
+ print_res_top(result);
+}
+
+
+static void print_res_top(MYSQL_RES *result)
+{
+ uint i,length;
+ MYSQL_FIELD *field;
+
+ putchar('+');
+ mysql_field_seek(result,0);
+ while((field = mysql_fetch_field(result)))
+ {
+ if ((length=strlen(field->name)) > field->max_length)
+ field->max_length=length;
+ else
+ length=field->max_length;
+ for (i=length+2 ; i--> 0 ; )
+ putchar('-');
+ putchar('+');
+ }
+ putchar('\n');
+}
+
+
+static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur)
+{
+ uint i,length;
+ MYSQL_FIELD *field;
+ putchar('|');
+ mysql_field_seek(result,0);
+ for (i=0 ; i < mysql_num_fields(result); i++)
+ {
+ field = mysql_fetch_field(result);
+ length=field->max_length;
+ printf(" %-*s|",length+1,cur[i] ? (char*) cur[i] : "");
+ }
+ putchar('\n');
+}
diff --git a/client/password.c b/client/password.c
new file mode 100644
index 00000000000..0fd5861873a
--- /dev/null
+++ b/client/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/client/readline.cc b/client/readline.cc
new file mode 100644
index 00000000000..95e98cb90c2
--- /dev/null
+++ b/client/readline.cc
@@ -0,0 +1,216 @@
+/* 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 */
+
+/* readline for batch mode */
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "my_readline.h"
+
+static bool init_line_buffer(LINE_BUFFER *buffer,File file,ulong size,
+ ulong max_size);
+static bool init_line_buffer_from_string(LINE_BUFFER *buffer,my_string str);
+static uint fill_buffer(LINE_BUFFER *buffer);
+static char *intern_read_line(LINE_BUFFER *buffer,uint *out_length);
+
+
+LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file)
+{
+ LINE_BUFFER *line_buff;
+ if (!(line_buff=(LINE_BUFFER*) my_malloc(sizeof(*line_buff),MYF(MY_WME))))
+ return 0;
+ if (init_line_buffer(line_buff,fileno(file),IO_SIZE,max_size))
+ {
+ my_free((char*) line_buff,MYF(0));
+ return 0;
+ }
+ return line_buff;
+}
+
+
+char *batch_readline(LINE_BUFFER *line_buff)
+{
+ char *pos;
+ uint out_length;
+
+ if (!(pos=intern_read_line(line_buff,&out_length)))
+ return 0;
+ if (out_length && pos[out_length-1] == '\n')
+ out_length--; /* Remove '\n' */
+ pos[out_length]=0;
+ return pos;
+}
+
+
+void batch_readline_end(LINE_BUFFER *line_buff)
+{
+ if (line_buff)
+ {
+ my_free((gptr) line_buff->buffer,MYF(MY_ALLOW_ZERO_PTR));
+ my_free((char*) line_buff,MYF(0));
+ }
+}
+
+
+LINE_BUFFER *batch_readline_command(my_string str)
+{
+ LINE_BUFFER *line_buff;
+ if (!(line_buff=(LINE_BUFFER*) my_malloc(sizeof(*line_buff),MYF(MY_WME))))
+ return 0;
+ if (init_line_buffer_from_string(line_buff,str))
+ {
+ my_free((char*) line_buff,MYF(0));
+ return 0;
+ }
+ return line_buff;
+}
+
+
+/*****************************************************************************
+ Functions to handle buffered readings of lines from a stream
+******************************************************************************/
+
+static bool
+init_line_buffer(LINE_BUFFER *buffer,File file,ulong size,ulong max_buffer)
+{
+ bzero((char*) buffer,sizeof(buffer[0]));
+ buffer->file=file;
+ buffer->bufread=size;
+ buffer->max_size=max_buffer;
+ if (!(buffer->buffer = (char*) my_malloc(buffer->bufread+1,
+ MYF(MY_WME | MY_FAE))))
+ return 1;
+ buffer->end_of_line=buffer->end=buffer->buffer;
+ buffer->buffer[0]=0; /* For easy start test */
+ return 0;
+}
+
+
+static bool init_line_buffer_from_string(LINE_BUFFER *buffer,my_string str)
+{
+ uint length;
+ bzero((char*) buffer,sizeof(buffer[0]));
+ length=strlen(str);
+ if (!(buffer->buffer=buffer->start_of_line=buffer->end_of_line=
+ (char*)my_malloc(length+2,MYF(MY_FAE))))
+ return 1;
+ memcpy(buffer->buffer,str,length);
+ buffer->buffer[length]='\n';
+ buffer->buffer[length+1]=0;
+ buffer->end=buffer->buffer+length+1;
+ buffer->eof=1;
+ buffer->max_size=1;
+ return 0;
+}
+
+
+static void free_line_buffer(LINE_BUFFER *buffer)
+{
+ if (buffer->buffer)
+ {
+ my_free((gptr) buffer->buffer,MYF(0));
+ buffer->buffer=0;
+ }
+}
+
+
+/* Fill the buffer retaining the last n bytes at the beginning of the
+ newly filled buffer (for backward context). Returns the number of new
+ bytes read from disk. */
+
+
+static uint fill_buffer(LINE_BUFFER *buffer)
+{
+ uint read_count;
+ uint bufbytes= (uint) (buffer->end - buffer->start_of_line);
+
+ if (buffer->eof)
+ return 0; /* Everything read */
+
+ /* See if we need to grow the buffer. */
+
+ for (;;)
+ {
+ uint start_offset=(uint) (buffer->start_of_line - buffer->buffer);
+ read_count=(buffer->bufread - bufbytes)/IO_SIZE;
+ if ((read_count*=IO_SIZE))
+ break;
+ buffer->bufread *= 2;
+ if (!(buffer->buffer = (char*) my_realloc(buffer->buffer,
+ buffer->bufread+1,
+ MYF(MY_WME | MY_FAE))))
+ return (uint) -1;
+ buffer->start_of_line=buffer->buffer+start_offset;
+ buffer->end=buffer->buffer+bufbytes;
+ }
+
+ /* Shift stuff down. */
+ if (buffer->start_of_line != buffer->buffer)
+ {
+ bmove(buffer->buffer,buffer->start_of_line,(uint) bufbytes);
+ buffer->end=buffer->buffer+bufbytes;
+ }
+
+ /* Read in new stuff. */
+ if ((read_count= my_read(buffer->file, (byte*) buffer->end, read_count,
+ MYF(MY_WME))) == MY_FILE_ERROR)
+ return read_count;
+
+ DBUG_PRINT("fill_buff", ("Got %d bytes", read_count));
+
+ /* Kludge to pretend every nonempty file ends with a newline. */
+ if (!read_count && bufbytes && buffer->end[-1] != '\n')
+ {
+ buffer->eof = read_count = 1;
+ *buffer->end = '\n';
+ }
+ buffer->end_of_line=(buffer->start_of_line=buffer->buffer)+bufbytes;
+ buffer->end+=read_count;
+ *buffer->end=0; /* Sentinel */
+ return read_count;
+}
+
+
+
+char *intern_read_line(LINE_BUFFER *buffer,uint *out_length)
+{
+ char *pos;
+ uint length;
+ DBUG_ENTER("intern_read_line");
+
+ buffer->start_of_line=buffer->end_of_line;
+ for (;;)
+ {
+ pos=buffer->end_of_line;
+ while (*pos != '\n' && *pos)
+ pos++;
+ if (pos == buffer->end)
+ {
+ if ((uint) (pos - buffer->start_of_line) < buffer->max_size)
+ {
+ if (!(length=fill_buffer(buffer)) || length == (uint) -1)
+ DBUG_RETURN(0);
+ continue;
+ }
+ pos--; /* break line here */
+ }
+ buffer->end_of_line=pos+1;
+ *out_length=(uint) (pos + 1 - buffer->eof - buffer->start_of_line);
+ DBUG_RETURN(buffer->start_of_line);
+ }
+}
diff --git a/client/select_test.c b/client/select_test.c
new file mode 100644
index 00000000000..049f2b908be
--- /dev/null
+++ b/client/select_test.c
@@ -0,0 +1,75 @@
+/* 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 */
+
+
+#if defined(_WIN32) || defined(_WIN64)
+#include <windows.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include "mysql.h"
+
+#define SELECT_QUERY "select name from test where num = %d"
+
+
+int main(int argc, char **argv)
+{
+ int count, num;
+ MYSQL mysql,*sock;
+ MYSQL_RES *res;
+ char qbuf[160];
+
+ if (argc != 3)
+ {
+ fprintf(stderr,"usage : select_test <dbname> <num>\n\n");
+ exit(1);
+ }
+
+ mysql_init(&mysql);
+ if (!(sock = mysql_real_connect(&mysql,NULL,0,0,argv[1],0,NULL,0)))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n\n",mysql_error(&mysql));
+ perror("");
+ exit(1);
+ }
+
+ count = 0;
+ num = atoi(argv[2]);
+ while (count < num)
+ {
+ sprintf(qbuf,SELECT_QUERY,count);
+ if(mysql_query(sock,qbuf))
+ {
+ fprintf(stderr,"Query failed (%s)\n",mysql_error(sock));
+ exit(1);
+ }
+ if (!(res=mysql_store_result(sock)))
+ {
+ fprintf(stderr,"Couldn't get result from %s\n",
+ mysql_error(sock));
+ exit(1);
+ }
+#ifdef TEST
+ printf("number of fields: %d\n",mysql_num_fields(res));
+#endif
+ mysql_free_result(res);
+ count++;
+ }
+ mysql_close(sock);
+ exit(0);
+ return 0; /* Keep some compilers happy */
+}
diff --git a/client/showdb_test.c b/client/showdb_test.c
new file mode 100644
index 00000000000..f4c25999fe5
--- /dev/null
+++ b/client/showdb_test.c
@@ -0,0 +1,80 @@
+/* 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 program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef __WIN__
+#include <windows.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include "mysql.h"
+
+#define SELECT_QUERY "select name from test where num = %d"
+
+
+int main(int argc, char **argv)
+{
+ int count, num;
+ MYSQL mysql,*sock;
+ MYSQL_RES *res;
+ char qbuf[160];
+
+ if (argc != 3)
+ {
+ fprintf(stderr,"usage : select_test <dbname> <num>\n\n");
+ exit(1);
+ }
+
+ mysql_init(&mysql);
+ if (!(sock = mysql_real_connect(&mysql,NULL,0,0,argv[1],0,NULL,0)))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n\n",mysql_error(&mysql));
+ perror("");
+ exit(1);
+ }
+
+ count = 0;
+ num = atoi(argv[2]);
+ while (count < num)
+ {
+ sprintf(qbuf,SELECT_QUERY,count);
+ if(!(res=mysql_list_dbs(sock,NULL)))
+ {
+ fprintf(stderr,"Query failed (%s)\n",mysql_error(sock));
+ exit(1);
+ }
+ printf("number of fields: %d\n",mysql_num_rows(res));
+ mysql_free_result(res);
+ count++;
+ }
+ mysql_close(sock);
+ exit(0);
+ return 0; /* Keep some compilers happy */
+}
diff --git a/client/sql_string.cc b/client/sql_string.cc
new file mode 100644
index 00000000000..5c3e1068649
--- /dev/null
+++ b/client/sql_string.cc
@@ -0,0 +1,728 @@
+/* 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 originally from the mysql distribution. Coded by monty */
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#ifdef HAVE_FCONVERT
+#include <floatingpoint.h>
+#endif
+
+extern gptr sql_alloc(unsigned size);
+extern void sql_element_free(void *ptr);
+
+#include "sql_string.h"
+
+/*****************************************************************************
+** String functions
+*****************************************************************************/
+
+bool String::real_alloc(uint32 arg_length)
+{
+ arg_length=ALIGN_SIZE(arg_length+1);
+ if (Alloced_length < arg_length)
+ {
+ free();
+ if (!(Ptr=(char*) my_malloc(arg_length,MYF(MY_WME))))
+ {
+ str_length=0;
+ return TRUE;
+ }
+ Alloced_length=arg_length;
+ alloced=1;
+ }
+ Ptr[0]=0;
+ str_length=0;
+ return FALSE;
+}
+
+
+/*
+** Check that string is big enough. Set string[alloc_length] to 0
+** (for C functions)
+*/
+
+bool String::realloc(uint32 alloc_length)
+{
+ uint32 len=ALIGN_SIZE(alloc_length+1);
+ if (Alloced_length < len)
+ {
+ char *new_ptr;
+ if (alloced)
+ {
+ if ((new_ptr= (char*) my_realloc(Ptr,len,MYF(MY_WME))))
+ {
+ Ptr=new_ptr;
+ Alloced_length=len;
+ }
+ else
+ return TRUE; // Signal error
+ }
+ else if ((new_ptr= (char*) my_malloc(len,MYF(MY_WME))))
+ {
+ memcpy(new_ptr,Ptr,str_length);
+ new_ptr[str_length]=0;
+ Ptr=new_ptr;
+ Alloced_length=len;
+ alloced=1;
+ }
+ else
+ return TRUE; // Signal error
+ }
+ Ptr[alloc_length]=0; // This make other funcs shorter
+ return FALSE;
+}
+
+
+#ifdef NOT_NEEDED
+bool String::set(long num)
+{
+ if (alloc(14))
+ return TRUE;
+ str_length=(uint32) (int10_to_str(num,Ptr,-10)-Ptr);
+ return FALSE;
+}
+#endif
+
+bool String::set(longlong num)
+{
+ if (alloc(21))
+ return TRUE;
+ str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr);
+ return FALSE;
+}
+
+bool String::set(ulonglong num)
+{
+ if (alloc(21))
+ return TRUE;
+ str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr);
+ return FALSE;
+}
+
+bool String::set(double num,uint decimals)
+{
+ char buff[331];
+ if (decimals >= NOT_FIXED_DEC)
+ {
+ sprintf(buff,"%.14g",num); // Enough for a DATETIME
+ return copy(buff,strlen(buff));
+ }
+#ifdef HAVE_FCONVERT
+ int decpt,sign;
+ char *pos,*to;
+
+ VOID(fconvert(num,(int) decimals,&decpt,&sign,buff+1));
+ if (!isdigit(buff[1]))
+ { // Nan or Inf
+ pos=buff+1;
+ if (sign)
+ {
+ buff[0]='-';
+ pos=buff;
+ }
+ return copy(pos,strlen(pos));
+ }
+ if (alloc((uint32) ((uint32) decpt+3+decimals)))
+ return TRUE;
+ to=Ptr;
+ if (sign)
+ *to++='-';
+
+ pos=buff+1;
+ if (decpt < 0)
+ { /* value is < 0 */
+ *to++='0';
+ if (!decimals)
+ goto end;
+ *to++='.';
+ if ((uint32) -decpt > decimals)
+ decpt= - (int) decimals;
+ decimals=(uint32) ((int) decimals+decpt);
+ while (decpt++ < 0)
+ *to++='0';
+ }
+ else if (decpt == 0)
+ {
+ *to++= '0';
+ if (!decimals)
+ goto end;
+ *to++='.';
+ }
+ else
+ {
+ while (decpt-- > 0)
+ *to++= *pos++;
+ if (!decimals)
+ goto end;
+ *to++='.';
+ }
+ while (decimals--)
+ *to++= *pos++;
+
+end:
+ *to=0;
+ str_length=(uint32) (to-Ptr);
+ return FALSE;
+#else
+#ifdef HAVE_SNPRINTF_
+ snprintf(buff,sizeof(buff), "%.*f",(int) decimals,num);
+#else
+ sprintf(buff,"%.*f",(int) decimals,num);
+#endif
+ return copy(buff,strlen(buff));
+#endif
+}
+
+
+bool String::copy()
+{
+ if (!alloced)
+ {
+ Alloced_length=0; // Force realloc
+ return realloc(str_length);
+ }
+ return FALSE;
+}
+
+bool String::copy(const String &str)
+{
+ if (alloc(str.str_length))
+ return TRUE;
+ str_length=str.str_length;
+ bmove(Ptr,str.Ptr,str_length); // May be overlapping
+ Ptr[str_length]=0;
+ return FALSE;
+}
+
+bool String::copy(const char *str,uint32 arg_length)
+{
+ if (alloc(arg_length))
+ return TRUE;
+ str_length=arg_length;
+ memcpy(Ptr,str,arg_length);
+ Ptr[arg_length]=0;
+ return FALSE;
+}
+
+/* This is used by mysql.cc */
+
+bool String::fill(uint32 max_length,char fill_char)
+{
+ if (str_length > max_length)
+ Ptr[str_length=max_length]=0;
+ else
+ {
+ if (realloc(max_length))
+ return TRUE;
+ bfill(Ptr+str_length,max_length-str_length,fill_char);
+ str_length=max_length;
+ }
+ return FALSE;
+}
+
+void String::strip_sp()
+{
+ while (str_length && isspace(Ptr[str_length-1]))
+ str_length--;
+}
+
+bool String::append(const String &s)
+{
+ if (realloc(str_length+s.length()))
+ return TRUE;
+ memcpy(Ptr+str_length,s.ptr(),s.length());
+ str_length+=s.length();
+ return FALSE;
+}
+
+bool String::append(const char *s,uint32 arg_length)
+{
+ if (!arg_length) // Default argument
+ arg_length=strlen(s);
+ if (realloc(str_length+arg_length))
+ return TRUE;
+ memcpy(Ptr+str_length,s,arg_length);
+ str_length+=arg_length;
+ return FALSE;
+}
+
+uint32 String::numchars()
+{
+#ifdef USE_MB
+ register uint32 n=0,mblen;
+ register const char *mbstr=Ptr;
+ register const char *end=mbstr+str_length;
+ if (use_mb(default_charset_info))
+ {
+ while (mbstr < end) {
+ if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
+ else ++mbstr;
+ ++n;
+ }
+ return n;
+ }
+ else
+#endif
+ return str_length;
+}
+
+int String::charpos(int i,uint32 offset)
+{
+#ifdef USE_MB
+ register uint32 mblen;
+ register const char *mbstr=Ptr+offset;
+ register const char *end=Ptr+str_length;
+ if (use_mb(default_charset_info))
+ {
+ if (i<=0) return i;
+ while (i && mbstr < end) {
+ if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
+ else ++mbstr;
+ --i;
+ }
+ if ( INT_MAX32-i <= (int) (mbstr-Ptr-offset))
+ return INT_MAX32;
+ else
+ return (mbstr-Ptr-offset)+i;
+ }
+ else
+#endif
+ return i;
+}
+
+int String::strstr(const String &s,uint32 offset)
+{
+ if (s.length()+offset <= str_length)
+ {
+ if (!s.length())
+ return offset; // Empty string is always found
+
+ register const char *str = Ptr+offset;
+ register const char *search=s.ptr();
+ const char *end=Ptr+str_length-s.length()+1;
+ const char *search_end=s.ptr()+s.length();
+skipp:
+ while (str != end)
+ {
+ if (*str++ == *search)
+ {
+ register char *i,*j;
+ i=(char*) str; j=(char*) search+1;
+ while (j != search_end)
+ if (*i++ != *j++) goto skipp;
+ return (int) (str-Ptr) -1;
+ }
+ }
+ }
+ return -1;
+}
+
+
+/*
+** Search string from end. Offset is offset to the end of string
+*/
+
+int String::strrstr(const String &s,uint32 offset)
+{
+ if (s.length() <= offset && offset <= str_length)
+ {
+ if (!s.length())
+ return offset; // Empty string is always found
+ register const char *str = Ptr+offset-1;
+ register const char *search=s.ptr()+s.length()-1;
+
+ const char *end=Ptr+s.length()-2;
+ const char *search_end=s.ptr()-1;
+skipp:
+ while (str != end)
+ {
+ if (*str-- == *search)
+ {
+ register char *i,*j;
+ i=(char*) str; j=(char*) search-1;
+ while (j != search_end)
+ if (*i-- != *j--) goto skipp;
+ return (int) (i-Ptr) +1;
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+** replace substring with string
+** If wrong parameter or not enough memory, do nothing
+*/
+
+
+bool String::replace(uint32 offset,uint32 arg_length,const String &to)
+{
+ long diff = (long) to.length()-(long) arg_length;
+ if (offset+arg_length <= str_length)
+ {
+ if (diff < 0)
+ {
+ memcpy(Ptr+offset,to.ptr(),to.length());
+ bmove(Ptr+offset+to.length(),Ptr+offset+arg_length,
+ str_length-offset-arg_length);
+ }
+ else
+ {
+ if (diff)
+ {
+ if (realloc(str_length+(uint32) diff))
+ return TRUE;
+ bmove_upp(Ptr+str_length+diff,Ptr+str_length,
+ str_length-offset-arg_length);
+ }
+ memcpy(Ptr+offset,to.ptr(),to.length());
+ }
+ str_length+=(uint32) diff;
+ }
+ return FALSE;
+}
+
+
+int sortcmp(const String *x,const String *y)
+{
+ const char *s= x->ptr();
+ const char *t= y->ptr();
+ uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
+
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ {
+#ifndef CMP_ENDSPACE
+ while (x_len && isspace(s[x_len-1]))
+ x_len--;
+ while (y_len && isspace(t[y_len-1]))
+ y_len--;
+#endif
+ return my_strnncoll(default_charset_info,
+ (unsigned char *)s,x_len,(unsigned char *)t,y_len);
+ }
+ else
+ {
+#endif /* USE_STRCOLL */
+ x_len-=len; // For easy end space test
+ y_len-=len;
+ while (len--)
+ {
+ if (my_sort_order[(uchar) *s++] != my_sort_order[(uchar) *t++])
+ return ((int) my_sort_order[(uchar) s[-1]] -
+ (int) my_sort_order[(uchar) t[-1]]);
+ }
+#ifndef CMP_ENDSPACE
+ /* Don't compare end space in strings */
+ {
+ if (y_len)
+ {
+ const char *end=t+y_len;
+ for (; t != end ; t++)
+ if (!isspace(*t))
+ return -1;
+ }
+ else
+ {
+ const char *end=s+x_len;
+ for (; s != end ; s++)
+ if (!isspace(*s))
+ return 1;
+ }
+ return 0;
+ }
+#else
+ return (int) (x_len-y_len);
+#endif /* CMP_ENDSPACE */
+#ifdef USE_STRCOLL
+ }
+#endif
+}
+
+
+int stringcmp(const String *x,const String *y)
+{
+ const char *s= x->ptr();
+ const char *t= y->ptr();
+ uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
+
+ while (len--)
+ {
+ if (*s++ != *t++)
+ return ((int) (uchar) s[-1] - (int) (uchar) t[-1]);
+ }
+ return (int) (x_len-y_len);
+}
+
+
+String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
+{
+ if (from->Alloced_length >= from_length)
+ return from;
+ if (from->alloced || !to || from == to)
+ {
+ (void) from->realloc(from_length);
+ return from;
+ }
+ if (to->realloc(from_length))
+ return from; // Actually an error
+ to->str_length=min(from->str_length,from_length);
+ memcpy(to->Ptr,from->Ptr,to->str_length);
+ return to;
+}
+
+/* Make it easier to handle different charactersets */
+
+#ifdef USE_MB
+#define INC_PTR(A,B) A+=((use_mb_flag && \
+ my_ismbchar(default_charset_info,A,B)) ? \
+ my_ismbchar(default_charset_info,A,B) : 1)
+#else
+#define INC_PTR(A,B) A++
+#endif
+
+/*
+** Compare string against string with wildcard
+** 0 if matched
+** -1 if not matched with wildcard
+** 1 if matched with wildcard
+*/
+
+#ifdef LIKE_CMP_TOUPPER
+#define likeconv(A) (uchar) toupper(A)
+#else
+#define likeconv(A) (uchar) my_sort_order[(uchar) (A)]
+#endif
+
+static int wild_case_compare(const char *str,const char *str_end,
+ const char *wildstr,const char *wildend,
+ char escape)
+{
+ int result= -1; // Not found, using wildcards
+#ifdef USE_MB
+ bool use_mb_flag=use_mb(default_charset_info);
+#endif
+ while (wildstr != wildend)
+ {
+ while (*wildstr != wild_many && *wildstr != wild_one)
+ {
+ if (*wildstr == escape && wildstr+1 != wildend)
+ wildstr++;
+#ifdef USE_MB
+ int l;
+ if (use_mb_flag &&
+ (l = my_ismbchar(default_charset_info, wildstr, wildend)))
+ {
+ if (str+l > str_end || memcmp(str, wildstr, l) != 0)
+ return 1;
+ str += l;
+ wildstr += l;
+ }
+ else
+#endif
+ if (str == str_end || likeconv(*wildstr++) != likeconv(*str++))
+ return(1); // No match
+ if (wildstr == wildend)
+ return (str != str_end); // Match if both are at end
+ result=1; // Found an anchor char
+ }
+ if (*wildstr == wild_one)
+ {
+ do
+ {
+ if (str == str_end) // Skipp one char if possible
+ return (result);
+ INC_PTR(str,str_end);
+ } while (++wildstr < wildend && *wildstr == wild_one);
+ if (wildstr == wildend)
+ break;
+ }
+ if (*wildstr == wild_many)
+ { // Found wild_many
+ wildstr++;
+ /* Remove any '%' and '_' from the wild search string */
+ for ( ; wildstr != wildend ; wildstr++)
+ {
+ if (*wildstr == wild_many)
+ continue;
+ if (*wildstr == wild_one)
+ {
+ if (str == str_end)
+ return (-1);
+ INC_PTR(str,str_end);
+ continue;
+ }
+ break; // Not a wild character
+ }
+ if (wildstr == wildend)
+ return(0); // Ok if wild_many is last
+ if (str == str_end)
+ return -1;
+
+ uchar cmp;
+ if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
+ cmp= *++wildstr;
+#ifdef USE_MB
+ const char* mb = wildstr;
+ int mblen;
+ if (use_mb_flag)
+ mblen = my_ismbchar(default_charset_info, wildstr, wildend);
+#endif
+ INC_PTR(wildstr,wildend); // This is compared trough cmp
+ cmp=likeconv(cmp);
+ do
+ {
+#ifdef USE_MB
+ if (use_mb_flag)
+ {
+ for (;;)
+ {
+ if (str >= str_end)
+ return -1;
+ if (mblen)
+ {
+ if (str+mblen <= str_end && memcmp(str, mb, mblen) == 0)
+ {
+ str += mblen;
+ break;
+ }
+ }
+ else if (!my_ismbchar(default_charset_info, str, str_end) &&
+ likeconv(*str) == cmp)
+ {
+ str++;
+ break;
+ }
+ INC_PTR(str, str_end);
+ }
+ }
+ else
+ {
+#endif /* USE_MB */
+ while (str != str_end && likeconv(*str) != cmp)
+ str++;
+ if (str++ == str_end) return (-1);
+#ifdef USE_MB
+ }
+#endif
+ {
+ int tmp=wild_case_compare(str,str_end,wildstr,wildend,escape);
+ if (tmp <= 0)
+ return (tmp);
+ }
+ } while (str != str_end && wildstr[0] != wild_many);
+ return(-1);
+ }
+ }
+ return (str != str_end ? 1 : 0);
+}
+
+
+int wild_case_compare(String &match,String &wild, char escape)
+{
+ return wild_case_compare(match.ptr(),match.ptr()+match.length(),
+ wild.ptr(), wild.ptr()+wild.length(),escape);
+}
+
+/*
+** The following is used when using LIKE on binary strings
+*/
+
+static int wild_compare(const char *str,const char *str_end,
+ const char *wildstr,const char *wildend,char escape)
+{
+ int result= -1; // Not found, using wildcards
+ while (wildstr != wildend)
+ {
+ while (*wildstr != wild_many && *wildstr != wild_one)
+ {
+ if (*wildstr == escape && wildstr+1 != wildend)
+ wildstr++;
+ if (str == str_end || *wildstr++ != *str++)
+ return(1);
+ if (wildstr == wildend)
+ return (str != str_end); // Match if both are at end
+ result=1; // Found an anchor char
+ }
+ if (*wildstr == wild_one)
+ {
+ do
+ {
+ if (str == str_end) // Skipp one char if possible
+ return (result);
+ str++;
+ } while (*++wildstr == wild_one && wildstr != wildend);
+ if (wildstr == wildend)
+ break;
+ }
+ if (*wildstr == wild_many)
+ { // Found wild_many
+ wildstr++;
+ /* Remove any '%' and '_' from the wild search string */
+ for ( ; wildstr != wildend ; wildstr++)
+ {
+ if (*wildstr == wild_many)
+ continue;
+ if (*wildstr == wild_one)
+ {
+ if (str == str_end)
+ return (-1);
+ str++;
+ continue;
+ }
+ break; // Not a wild character
+ }
+ if (wildstr == wildend)
+ return(0); // Ok if wild_many is last
+ if (str == str_end)
+ return -1;
+
+ char cmp;
+ if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
+ cmp= *++wildstr;
+ wildstr++; // This is compared trough cmp
+ do
+ {
+ while (str != str_end && *str != cmp)
+ str++;
+ if (str++ == str_end) return (-1);
+ {
+ int tmp=wild_compare(str,str_end,wildstr,wildend,escape);
+ if (tmp <= 0)
+ return (tmp);
+ }
+ } while (str != str_end && wildstr[0] != wild_many);
+ return(-1);
+ }
+ }
+ return (str != str_end ? 1 : 0);
+}
+
+
+int wild_compare(String &match,String &wild, char escape)
+{
+ return wild_compare(match.ptr(),match.ptr()+match.length(),
+ wild.ptr(), wild.ptr()+wild.length(),escape);
+}
diff --git a/client/sql_string.h b/client/sql_string.h
new file mode 100644
index 00000000000..56a0a9b4eb2
--- /dev/null
+++ b/client/sql_string.h
@@ -0,0 +1,183 @@
+/* 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 originally from the mysql distribution. Coded by monty */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#ifndef NOT_FIXED_DEC
+#define NOT_FIXED_DEC 31
+#endif
+
+class String
+{
+ char *Ptr;
+ uint32 str_length,Alloced_length;
+ bool alloced;
+public:
+ String()
+ { Ptr=0; str_length=Alloced_length=0; alloced=0; }
+ String(uint32 length_arg)
+ { alloced=0; Alloced_length=0; (void) real_alloc(length_arg); }
+ String(const char *str)
+ { Ptr=(char*) str; str_length=strlen(str); Alloced_length=0; alloced=0;}
+ String(const char *str,uint32 len)
+ { Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0;}
+ String(char *str,uint32 len)
+ { Ptr=(char*) str; Alloced_length=str_length=len; alloced=0;}
+ String(const String &str)
+ { Ptr=str.Ptr ; str_length=str.str_length ;
+ Alloced_length=str.Alloced_length; alloced=0; }
+
+ static void *operator new(size_t size) { return (void*) sql_alloc(size); }
+ static void operator delete(void *ptr_arg,size_t size) /*lint -e715 */
+ { sql_element_free(ptr_arg); }
+ ~String() { free(); }
+
+ inline uint32 length() const { return str_length;}
+ inline uint32 alloced_length() const { return Alloced_length;}
+ inline char& operator [] (uint32 i) const { return Ptr[i]; }
+ inline void length(uint32 len) { str_length=len ; }
+ inline bool is_empty() { return (str_length == 0); }
+ inline const char *ptr() const { return Ptr; }
+ inline char *c_ptr()
+ {
+ if (!Ptr || Ptr[str_length]) /* Should be safe */
+ (void) realloc(str_length);
+ return Ptr;
+ }
+ inline char *c_ptr_quick()
+ {
+ if (Ptr && str_length < Alloced_length)
+ Ptr[str_length]=0;
+ return Ptr;
+ }
+
+ void set(String &str,uint32 offset,uint32 arg_length)
+ {
+ free();
+ Ptr=(char*) str.ptr()+offset; str_length=arg_length; alloced=0;
+ if (str.Alloced_length)
+ Alloced_length=str.Alloced_length-offset;
+ else
+ Alloced_length=0;
+ }
+ inline void set(char *str,uint32 arg_length)
+ {
+ free();
+ Ptr=(char*) str; str_length=Alloced_length=arg_length ; alloced=0;
+ }
+ inline void set(const char *str,uint32 arg_length)
+ {
+ free();
+ Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0;
+ }
+ inline void set_quick(char *str,uint32 arg_length)
+ {
+ if (!alloced)
+ {
+ Ptr=(char*) str; str_length=Alloced_length=arg_length;
+ }
+ }
+ bool set(longlong num);
+ /* bool set(long num); */
+ bool set(ulonglong num);
+ bool set(double num,uint decimals=2);
+ inline void free()
+ {
+ if (alloced)
+ {
+ alloced=0;
+ Alloced_length=0;
+ my_free(Ptr,MYF(0));
+ Ptr=0;
+ }
+ }
+
+ inline bool alloc(uint32 arg_length)
+ {
+ if (arg_length < Alloced_length)
+ return 0;
+ return real_alloc(arg_length);
+ }
+ bool real_alloc(uint32 arg_length); // Empties old string
+ bool realloc(uint32 arg_length);
+ inline void shrink(uint32 arg_length) // Shrink buffer
+ {
+ if (arg_length < Alloced_length)
+ {
+ char *new_ptr;
+ if (!(new_ptr=my_realloc(Ptr,arg_length,MYF(0))))
+ {
+ (void) my_free(Ptr,MYF(0));
+ real_alloc(arg_length);
+ }
+ else
+ {
+ Ptr=new_ptr;
+ Alloced_length=arg_length;
+ }
+ }
+ }
+ bool is_alloced() { return alloced; }
+ inline String& operator = (const String &s)
+ {
+ if (&s != this)
+ {
+ free();
+ Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length;
+ alloced=0;
+ }
+ return *this;
+ }
+
+ bool copy(); // Alloc string if not alloced
+ bool copy(const String &s); // Allocate new string
+ bool copy(const char *s,uint32 arg_length); // Allocate new string
+ bool append(const String &s);
+ bool append(const char *s,uint32 arg_length=0);
+ int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
+ int strrstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
+ bool replace(uint32 offset,uint32 arg_length,const String &to);
+ inline bool append(char chr)
+ {
+ if (str_length < Alloced_length)
+ {
+ Ptr[str_length++]=chr;
+ }
+ else
+ {
+ if (realloc(str_length+1))
+ return 1;
+ Ptr[str_length++]=chr;
+ }
+ return 0;
+ }
+ bool fill(uint32 max_length,char fill);
+ void strip_sp();
+ inline void caseup() { ::caseup(Ptr,str_length); }
+ inline void casedn() { ::casedn(Ptr,str_length); }
+ friend int sortcmp(const String *a,const String *b);
+ friend int stringcmp(const String *a,const String *b);
+ friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
+ friend int wild_case_compare(String &match,String &wild,char escape);
+ friend int wild_compare(String &match,String &wild,char escape);
+ uint32 numchars();
+ int charpos(int i,uint32 offset=0);
+};
diff --git a/client/ssl_test.c b/client/ssl_test.c
new file mode 100644
index 00000000000..d1ec1776696
--- /dev/null
+++ b/client/ssl_test.c
@@ -0,0 +1,95 @@
+/* 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 program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef __WIN__
+#include <windows.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include "mysql.h"
+#include "config.h"
+#define SELECT_QUERY "select name from test where num = %d"
+
+
+int main(int argc, char **argv)
+{
+#ifdef HAVE_OPENSSL
+ int count, num;
+ MYSQL mysql,*sock;
+ MYSQL_RES *res;
+ char qbuf[160];
+
+ if (argc != 3)
+ {
+ fprintf(stderr,"usage : ssl_test <dbname> <num>\n\n");
+ exit(1);
+ }
+
+ mysql_init(&mysql);
+#ifdef HAVE_OPENSSL
+ mysql_ssl_set(&mysql,"../SSL/MySQL-client-key.pem","../SSL/MySQL-client-cert.pem","../SSL/MySQL-ca-cert.pem","../SSL/");
+#endif
+ if (!(sock = mysql_real_connect(&mysql,"127.0.0.1",0,0,argv[1],3306,NULL,0)))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n\n",mysql_error(&mysql));
+ perror("");
+ exit(1);
+ }
+ printf("Cipher:%s\n",mysql_ssl_cipher(&mysql));
+ count = 0;
+ num = atoi(argv[2]);
+ while (count < num)
+ {
+ sprintf(qbuf,SELECT_QUERY,count);
+ if(mysql_query(sock,qbuf))
+ {
+ fprintf(stderr,"Query failed (%s)\n",mysql_error(sock));
+ exit(1);
+ }
+ if (!(res=mysql_store_result(sock)))
+ {
+ fprintf(stderr,"Couldn't get result from query failed\n",
+ mysql_error(sock));
+ exit(1);
+ }
+#ifdef TEST
+ printf("number of fields: %d\n",mysql_num_fields(res));
+#endif
+ mysql_free_result(res);
+ count++;
+ }
+ mysql_close(sock);
+#else /* HAVE_OPENSSL */
+ printf("ssl_test: SSL not configured.\n");
+#endif /* HAVE_OPENSSL */
+ exit(0);
+ return 0; /* Keep some compilers happy */
+}
diff --git a/client/thread_test.c b/client/thread_test.c
new file mode 100644
index 00000000000..def3381eb89
--- /dev/null
+++ b/client/thread_test.c
@@ -0,0 +1,283 @@
+/* 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 */
+
+#include <global.h>
+#include <my_sys.h>
+#include <my_pthread.h>
+#include "mysql.h"
+#include <getopt.h>
+
+#ifndef THREAD
+
+int main(int argc, char **argv)
+{
+ printf("This test must be compiled with multithread support to work\n");
+ exit(1);
+}
+#else
+
+static my_bool version,verbose;
+static uint thread_count,number_of_tests=1000,number_of_threads=2;
+static pthread_cond_t COND_thread_count;
+static pthread_mutex_t LOCK_thread_count;
+
+static char *database,*host,*user,*password,*unix_socket,*query;
+uint tcp_port;
+
+#ifndef __WIN__
+void *test_thread(void *arg)
+#else
+unsigned __stdcall test_thread(void *arg)
+#endif
+{
+ MYSQL *mysql;
+ uint count;
+
+ mysql=mysql_init(NULL);
+ if (!mysql_real_connect(mysql,host,user,password,database,tcp_port,
+ unix_socket,0))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n\n",mysql_error(mysql));
+ perror("");
+ goto end;
+ }
+ if (verbose) { putchar('*'); fflush(stdout); }
+ for (count=0 ; count < number_of_tests ; count++)
+ {
+ MYSQL_RES *res;
+ if (mysql_query(mysql,query))
+ {
+ fprintf(stderr,"Query failed (%s)\n",mysql_error(mysql));
+ goto end;
+ }
+ if (!(res=mysql_store_result(mysql)))
+ {
+ fprintf(stderr,"Couldn't get result from %s\n", mysql_error(mysql));
+ goto end;
+ }
+ mysql_free_result(res);
+ if (verbose) { putchar('.'); fflush(stdout); }
+ }
+end:
+ if (verbose) { putchar('#'); fflush(stdout); }
+ mysql_close(mysql);
+ pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ pthread_exit(0);
+ return 0;
+}
+
+
+static struct option long_options[] =
+{
+ {"help", no_argument, 0, '?'},
+ {"database", required_argument, 0, 'D'},
+ {"host", required_argument, 0, 'h'},
+ {"password", optional_argument, 0, 'p'},
+ {"user", required_argument, 0, 'u'},
+ {"version", no_argument, 0, 'V'},
+ {"verbose", no_argument, 0, 'v'},
+ {"query", required_argument, 0, 'Q'},
+ {"port", required_argument, 0, 'P'},
+ {"socket", required_argument, 0, 'S'},
+ {"test-count",required_argument, 0, 'c'},
+ {"thread-count",required_argument, 0, 't'},
+ {0, 0, 0, 0}
+};
+
+static const char *load_default_groups[]= { "client",0 };
+
+static void usage()
+{
+ printf("Connection to a mysql server with multiple threads\n");
+ if (version)
+ return;
+ puts("This software comes with ABSOLUTELY NO WARRANTY.\n");
+ printf("Usage: %s [OPTIONS] [database]\n", my_progname);
+ printf("\n\
+ -?, --help Display this help and exit\n\
+ -c #, --test-count=# Run test count times (default %d)\n",number_of_tests);
+ printf("\
+ -D, --database=.. Database to use\n\
+ -h, --host=... Connect to host\n\
+ -p[password], --password[=...]\n\
+ Password to use when connecting to server\n\
+ If password is not given it's asked from the tty.\n");
+ printf("\n\
+ -P --port=... Port number to use for connection\n\
+ -Q, --query=... Query to execute in each threads\n\
+ -S --socket=... Socket file to use for connection\n");
+ printf("\
+ -t --thread-count=# Number of threads to start (default: %d) \n\
+ -u, --user=# User for login if not current user\n\
+ -v, --verbose Write some progress indicators\n\
+ -V, --version Output version information and exit\n",
+ number_of_threads);
+
+ print_defaults("my",load_default_groups);
+
+ printf("\nExample usage:\n\n\
+%s -Q 'select * from mysql.user' -c %d -t %d\n",
+ my_progname, number_of_tests, number_of_threads);
+}
+
+
+static void get_options(int argc, char **argv)
+{
+ int c,option_index=0,error=0;
+ bool tty_password=0;
+ load_defaults("my",load_default_groups,&argc,&argv);
+
+ while ((c=getopt_long(argc,argv, "c:D:h:p::VQ:P:S:t:?I",
+ long_options, &option_index)) != EOF)
+ {
+ switch (c) {
+ case 'c':
+ number_of_tests=atoi(optarg);
+ break;
+ case 'D':
+ my_free(database,MYF(MY_ALLOW_ZERO_PTR));
+ database=my_strdup(optarg,MYF(MY_WME));
+ break;
+ case 'h':
+ host = optarg;
+ break;
+ case 'Q': /* Allow old 'q' option */
+ query= optarg;
+ break;
+ case 'p':
+ if (optarg)
+ {
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ password=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ }
+ else
+ tty_password=1;
+ break;
+ case 'u':
+ my_free(user,MYF(MY_ALLOW_ZERO_PTR));
+ user= my_strdup(optarg,MYF(0));
+ break;
+ case 'P':
+ tcp_port= (unsigned int) atoi(optarg);
+ break;
+ case 'S':
+ my_free(unix_socket,MYF(MY_ALLOW_ZERO_PTR));
+ unix_socket= my_strdup(optarg,MYF(0));
+ break;
+ case 't':
+ number_of_threads=atoi(optarg);
+ break;
+ case 'v':
+ verbose=1;
+ break;
+ case 'V':
+ version=1;
+ usage();
+ exit(0);
+ break;
+ default:
+ fprintf(stderr,"Illegal option character '%c'\n",opterr);
+ /* Fall through */
+ case '?':
+ case 'I': /* Info */
+ error++;
+ break;
+ }
+ }
+ if (error || argc != optind)
+ {
+ usage();
+ exit(1);
+ }
+ free_defaults(argv);
+ if (tty_password)
+ password=get_tty_password(NullS);
+ return;
+}
+
+
+int main(int argc, char **argv)
+{
+ pthread_t tid;
+ pthread_attr_t thr_attr;
+ int i,error;
+ MY_INIT(argv[0]);
+ get_options(argc,argv);
+
+ if ((error=pthread_cond_init(&COND_thread_count,NULL)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+ pthread_mutex_init(&LOCK_thread_count,NULL);
+
+ if ((error=pthread_attr_init(&thr_attr)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+ if ((error=pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED)))
+ {
+ fprintf(stderr,
+ "Got error: %d from pthread_attr_setdetachstate (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+
+ printf("Init ok. Creating %d threads\n",number_of_threads);
+ for (i=1 ; i <= number_of_threads ; i++)
+ {
+ int *param= &i;
+
+ if (verbose) { putchar('+'); fflush(stdout); }
+ pthread_mutex_lock(&LOCK_thread_count);
+ if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
+ {
+ fprintf(stderr,"\nGot error: %d from pthread_create (errno: %d) when creating thread: %i\n",
+ error,errno,i);
+ pthread_mutex_unlock(&LOCK_thread_count);
+ exit(1);
+ }
+ thread_count++;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ }
+
+ printf("Waiting for threads to finnish\n");
+ error=pthread_mutex_lock(&LOCK_thread_count);
+ while (thread_count)
+ {
+ if ((error=pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
+ fprintf(stderr,"\nGot error: %d from pthread_cond_wait\n",error);
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+ pthread_attr_destroy(&thr_attr);
+ printf("\nend\n");
+
+ my_end(0);
+ return 0;
+
+ exit(0);
+ return 0; /* Keep some compilers happy */
+}
+
+#endif /* THREAD */
diff --git a/client/violite.c b/client/violite.c
new file mode 100644
index 00000000000..f32c3c62a48
--- /dev/null
+++ b/client/violite.c
@@ -0,0 +1,394 @@
+/* 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 */
+
+#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) */
+ my_bool fcntl_set; /* Have we done any fcntl yet?*/
+ 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;
+}
+
+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);
+ }
+ 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)
+ {
+ vio_close(vio);
+ my_free((gptr) vio,MYF(0));
+ }
+}
+
+int vio_errno(Vio *vio)
+{
+ 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));
+ assert(vio->sd >= 0);
+#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));
+ assert(vio->sd >= 0);
+#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 (!vio->fcntl_set)
+ {
+ vio->fcntl_set = TRUE;
+ old_fcntl=vio->fcntl_mode = fcntl(vio->sd, F_GETFL);
+ }
+ 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 (!vio->fcntl_set)
+ {
+ vio->fcntl_set = TRUE;
+ old_fnctl=vio->fcntl_mode=0;
+ }
+ 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));
+ assert(vio->sd >= 0);
+
+#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)
+ {
+ assert(vio->sd >= 0);
+ 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)
+{
+ int en = errno;
+ return en == EAGAIN || en == EINTR || en == EWOULDBLOCK;
+}
+
+
+int vio_close(Vio * vio)
+{
+ int r;
+ DBUG_ENTER("vio_close");
+ assert(vio->sd >= 0); /* Vill also work on PIPE:s */
+#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
+#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_reset(vio,VIO_CLOSED,-1,0,TRUE); /* For debugging */
+ 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 */