diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/Makefile.am | 13 | ||||
-rw-r--r-- | client/client_priv.h | 4 | ||||
-rw-r--r-- | client/completion_hash.cc | 6 | ||||
-rw-r--r-- | client/completion_hash.h | 4 | ||||
-rw-r--r-- | client/connect_test.c | 65 | ||||
-rw-r--r-- | client/get_password.c | 1 | ||||
-rw-r--r-- | client/insert_test.c | 58 | ||||
-rw-r--r-- | client/list_test.c | 70 | ||||
-rw-r--r-- | client/mysql.cc | 771 | ||||
-rw-r--r-- | client/mysqladmin.c | 113 | ||||
-rw-r--r-- | client/mysqlbinlog.cc | 95 | ||||
-rw-r--r-- | client/mysqlcheck.c | 55 | ||||
-rw-r--r-- | client/mysqldump.c | 565 | ||||
-rw-r--r-- | client/mysqlimport.c | 55 | ||||
-rw-r--r-- | client/mysqlmanager-pwgen.c | 8 | ||||
-rw-r--r-- | client/mysqlshow.c | 54 | ||||
-rw-r--r-- | client/mysqltest.c | 397 | ||||
-rw-r--r-- | client/select_test.c | 73 | ||||
-rw-r--r-- | client/showdb_test.c | 66 | ||||
-rw-r--r-- | client/sql_string.cc | 452 | ||||
-rw-r--r-- | client/sql_string.h | 130 | ||||
-rw-r--r-- | client/ssl_test.c | 81 | ||||
-rw-r--r-- | client/thimble.cc | 107 | ||||
-rw-r--r-- | client/thread_test.c | 251 |
24 files changed, 1760 insertions, 1734 deletions
diff --git a/client/Makefile.am b/client/Makefile.am index 9c994814714..2c54ec45989 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -16,14 +16,12 @@ # 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.. $(openssl_includes) +#AUTOMAKE_OPTIONS = nostdinc +INCLUDES = -I$(top_srcdir)/include $(openssl_includes) LIBS = @CLIENT_LIBS@ LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysql/libmysqlclient.la bin_PROGRAMS = mysql mysqladmin mysqlcheck mysqlshow \ mysqldump mysqlimport mysqltest mysqlbinlog mysqlmanagerc mysqlmanager-pwgen -noinst_PROGRAMS = insert_test select_test thread_test noinst_HEADERS = sql_string.h completion_hash.h my_readline.h \ client_priv.h mysql_SOURCES = mysql.cc readline.cc sql_string.cc completion_hash.cc @@ -35,11 +33,9 @@ mysqlcheck_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) mysqltest_SOURCES= mysqltest.c mysqltest_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) -mysqlbinlog_SOURCES = mysqlbinlog.cc +mysqlbinlog_SOURCES = mysqlbinlog.cc ../mysys/mf_tempdir.c mysqlbinlog_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) mysqlmanagerc_SOURCES = mysqlmanagerc.c mysqlmanagerc_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) @@ -54,8 +50,5 @@ link_sources: @LN_CP_F@ $(top_srcdir)/sql/$$f $(srcdir)/$$f; \ done; -thread_test.o: thread_test.c - $(COMPILE) -c @MT_INCLUDES@ $(INCLUDES) $< - # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/client/client_priv.h b/client/client_priv.h index 5029f219494..f6d766b7ef9 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -38,4 +38,6 @@ enum options_client { OPT_CHARSETS_DIR=256, OPT_DEFAULT_CHARSET, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER, OPT_SHUTDOWN_TIMEOUT, OPT_LOCAL_INFILE, OPT_DELETE_MASTER_LOGS, - OPT_PROMPT, OPT_IGN_LINES,OPT_TRANSACTION, OPT_FRM }; + OPT_PROMPT, OPT_IGN_LINES,OPT_TRANSACTION,OPT_MYSQL_PROTOCOL, + OPT_SHARED_MEMORY_BASE_NAME, OPT_FRM, OPT_SKIP_OPTIMIZATION, + OPT_COMPATIBLE, OPT_RECONNECT, OPT_DELIMITER, OPT_SECURE_AUTH }; diff --git a/client/completion_hash.cc b/client/completion_hash.cc index ff5d0b28e41..536e7f9373a 100644 --- a/client/completion_hash.cc +++ b/client/completion_hash.cc @@ -27,7 +27,7 @@ #include <my_sys.h> #include "completion_hash.h" -uint hashpjw(char *arKey, uint nKeyLength) +uint hashpjw(const char *arKey, uint nKeyLength) { uint h = 0, g, i; @@ -111,7 +111,7 @@ int completion_hash_update(HashTable *ht, char *arKey, uint nKeyLength, return SUCCESS; } -static Bucket *completion_hash_find(HashTable *ht, char *arKey, +static Bucket *completion_hash_find(HashTable *ht, const char *arKey, uint nKeyLength) { uint h, nIndex; @@ -156,7 +156,7 @@ int completion_hash_exists(HashTable *ht, char *arKey, uint nKeyLength) return 0; } -Bucket *find_all_matches(HashTable *ht, char *str, uint length, +Bucket *find_all_matches(HashTable *ht, const char *str, uint length, uint *res_length) { Bucket *b; diff --git a/client/completion_hash.h b/client/completion_hash.h index c0853fddfe7..2595a445c9d 100644 --- a/client/completion_hash.h +++ b/client/completion_hash.h @@ -43,14 +43,14 @@ typedef struct hashtable { uint nTableSize; uint initialized; MEM_ROOT mem_root; - uint(*pHashFunction) (char *arKey, uint nKeyLength); + uint(*pHashFunction) (const 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_all_matches(HashTable *ht, const 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); diff --git a/client/connect_test.c b/client/connect_test.c deleted file mode 100644 index fd81ad635ad..00000000000 --- a/client/connect_test.c +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (C) 2000 MySQL 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 */ - -#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/get_password.c b/client/get_password.c index 5d78656ab0a..1b7b4e65a9f 100644 --- a/client/get_password.c +++ b/client/get_password.c @@ -23,7 +23,6 @@ #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 diff --git a/client/insert_test.c b/client/insert_test.c deleted file mode 100644 index 42691df6875..00000000000 --- a/client/insert_test.c +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (C) 2000 MySQL 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 */ - -#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_real_connect(&mysql,NULL,NULL,NULL,argv[1],0,NULL,0))) - { - fprintf(stderr,"Couldn't connect to engine!\n%s\n",mysql_error(&mysql)); - perror(""); - exit(1); - } - - 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 deleted file mode 100644 index 06bf16d2751..00000000000 --- a/client/list_test.c +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (C) 2000 MySQL 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 */ - -#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/mysql.cc b/client/mysql.cc index 370213d4fc4..df55ebcfab0 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -40,7 +40,11 @@ #include <signal.h> #include <violite.h> -const char *VER= "12.22"; +#if defined(USE_LIBEDIT_INTERFACE) && defined(HAVE_LOCALE_H) +#include <locale.h> +#endif + +const char *VER= "14.3"; /* Don't try to make a nice table if the data is too big */ #define MAX_COLUMN_LENGTH 1024 @@ -92,9 +96,9 @@ extern "C" { #endif #ifdef FN_NO_CASE_SENCE -#define cmp_database(A,B) my_strcasecmp((A),(B)) +#define cmp_database(cs,A,B) my_strcasecmp((cs), (A), (B)) #else -#define cmp_database(A,B) strcmp((A),(B)) +#define cmp_database(cs,A,B) strcmp((A),(B)) #endif #if !defined( __WIN__) && !defined( OS2) && !defined(__NETWARE__) && (!defined(HAVE_mit_thread) || !defined(THREAD)) @@ -104,6 +108,7 @@ extern "C" { #include "completion_hash.h" #define PROMPT_CHAR '\\' +#define DEFAULT_DELIMITER ";" typedef struct st_status { @@ -128,12 +133,14 @@ static my_bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0, opt_compress=0, using_opt_local_infile=0, vertical=0, line_numbers=1, column_names=1,opt_html=0, opt_xml=0,opt_nopager=1, opt_outfile=0, named_cmds= 0, - tty_password= 0, opt_nobeep=0; + tty_password= 0, opt_nobeep=0, opt_reconnect=1, + default_charset_used= 0, opt_secure_auth= 0; static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=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, - *current_prompt=0, *default_charset; + *current_prompt=0, *delimiter_str= 0, + *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; static char *histfile; static String glob_buffer,old_buffer; static String processed_prompt; @@ -155,7 +162,15 @@ static char pager[FN_REFLEN], outfile[FN_REFLEN]; static FILE *PAGER, *OUTFILE; static MEM_ROOT hash_mem_root; static uint prompt_counter; +static char delimiter[16]= DEFAULT_DELIMITER; +static uint delimiter_length= 1; +#ifdef HAVE_SMEM +static char *shared_memory_base_name=0; +#endif +static uint opt_protocol=0; +static CHARSET_INFO *charset_info= &my_charset_latin1; + #include "sslopt-vars.h" #ifndef DBUG_OFF @@ -176,7 +191,7 @@ static int com_quit(String *str,char*), com_use(String *str,char*), com_source(String *str, char*), com_rehash(String *str, char*), com_tee(String *str, char*), com_notee(String *str, char*), - com_prompt(String *str, char*); + com_prompt(String *str, char*), com_delimiter(String *str, char*); #ifdef USE_POPEN static int com_nopager(String *str, char*), com_pager(String *str, char*), @@ -186,7 +201,9 @@ static int com_nopager(String *str, char*), com_pager(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 int put_info(const char *str,INFO_TYPE info,uint error=0, + const char *sql_state=0); +static int put_error(MYSQL *mysql); static void safe_put_field(const char *pos,ulong length); static void xmlencode_print(const char *src, uint length); static void init_pager(); @@ -194,6 +211,7 @@ static void end_pager(); static void init_tee(const char *); static void end_tee(); static const char* construct_prompt(); +static char *get_arg(char *line, my_bool get_next_arg); static void init_username(); static void add_int_to_prompt(int toadd); @@ -209,8 +227,8 @@ typedef struct { } COMMANDS; static COMMANDS commands[] = { - { "help", 'h', com_help, 0, "Display this help." }, - { "?", '?', com_help, 0, "Synonym for `help'." }, + { "help", 'h', com_help, 1, "Display this help." }, + { "?", '?', com_help, 1, "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." }, @@ -243,7 +261,8 @@ static COMMANDS commands[] = { "Set outfile [to_outfile]. Append everything into given outfile." }, { "use", 'u', com_use, 1, "Use another database. Takes database name as argument." }, - + { "delimiter", 'd', com_delimiter, 1, + "Set query delimiter. " }, /* Get bash-like expansion for some commands */ { "create table", 0, 0, 0, ""}, { "create database", 0, 0, 0, ""}, @@ -271,14 +290,15 @@ static const char *server_default_groups[]= { "server", "embedded", "mysql_SERVER", 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); +extern "C" int add_history(const char *command); /* From readline directory */ +extern "C" int read_history(const char *command); +extern "C" int write_history(const 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 bool add_line(String &buffer,char *line,char *in_string, + bool *ml_comment); static void remove_cntrl(String &buffer); static void print_table_data(MYSQL_RES *result); static void print_table_data_html(MYSQL_RES *result); @@ -299,7 +319,8 @@ int main(int argc,char *argv[]) MY_INIT(argv[0]); DBUG_ENTER("main"); DBUG_PROCESS(argv[0]); - + + delimiter_str= delimiter; default_prompt = my_strdup(getenv("MYSQL_PS1") ? getenv("MYSQL_PS1") : "mysql> ",MYF(MY_WME)); @@ -350,6 +371,7 @@ int main(int argc,char *argv[]) if (!status.batch) ignore_errors=1; // Don't abort monitor signal(SIGINT, mysql_end); // Catch SIGINT to clean up + signal(SIGQUIT, mysql_end); // Catch SIGQUIT to clean up /* Run in interactive mode like the ingres/postgres monitor @@ -385,8 +407,11 @@ int main(int argc,char *argv[]) } } #endif - sprintf(buff, + sprintf(buff, "%s", "Type 'help;' or '\\h' for help. Type '\\c' to clear the buffer.\n"); +#ifdef NOT_YET + "Type 'help [[%]function name[%]]' to get help on usage of function.\n"); +#endif put_info(buff,INFO_INFO); status.exit_status=read_lines(1); // read lines and execute them if (opt_outfile) @@ -427,6 +452,9 @@ sig_handler mysql_end(int sig) my_free(full_username,MYF(MY_ALLOW_ZERO_PTR)); my_free(part_username,MYF(MY_ALLOW_ZERO_PTR)); my_free(default_prompt,MYF(MY_ALLOW_ZERO_PTR)); +#ifdef HAVE_SMEM + my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); +#endif my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR)); mysql_server_end(); free_defaults(defaults_argv); @@ -462,6 +490,8 @@ static struct my_option my_long_options[] = #endif {"database", 'D', "Database to use.", (gptr*) ¤t_db, (gptr*) ¤t_db, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"delimiter", OPT_DELIMITER, "Delimiter to be used.", (gptr*) &delimiter_str, + (gptr*) &delimiter_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"execute", 'e', "Execute command and quit. (Output like with --batch).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"vertical", 'E', "Print the output of a query (rows) vertically.", @@ -534,14 +564,23 @@ static struct my_option my_long_options[] = {"prompt", OPT_PROMPT, "Set the mysql prompt to this value.", (gptr*) ¤t_prompt, (gptr*) ¤t_prompt, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"quick", 'q', - "Don't cache result, print it row by row. This may slow down the server if the output is suspended. Doesn't use history file. ", + "Don't cache result, print it row by row. This may slow down the server if the output is suspended. Doesn't use history file.", (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"raw", 'r', "Write fields without conversion. Used with --batch", + {"raw", 'r', "Write fields without conversion. Used with --batch.", (gptr*) &opt_raw_data, (gptr*) &opt_raw_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"reconnect", OPT_RECONNECT, "Reconnect if the connection is lost. Disable with --disable-reconnect. This option is enabled by default.", + (gptr*) &opt_reconnect, (gptr*) &opt_reconnect, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"silent", 's', "Be more silent.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_SMEM + {"shared_memory_base_name", OPT_SHARED_MEMORY_BASE_NAME, + "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"socket", 'S', "Socket file to use for connection.", (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -563,7 +602,7 @@ static struct my_option my_long_options[] = {"i-am-a-dummy", 'U', "Synonym for option --safe-updates, -U.", (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"verbose", 'v', "Write more. (-v -v -v gives the table output format)", 0, + {"verbose", 'v', "Write more. (-v -v -v gives the table output format).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -584,6 +623,9 @@ static struct my_option my_long_options[] = {"max_join_size", OPT_MAX_JOIN_SIZE, "", (gptr*) &max_join_size, (gptr*) &max_join_size, 0, GET_ULONG, REQUIRED_ARG, 1000000L, 1, ~0L, 0, 1, 0}, + {"secure-auth", OPT_SECURE_AUTH, "Refuse client connecting to server if it" + " uses old (pre-4.1.1) protocol", (gptr*) &opt_secure_auth, + (gptr*) &opt_secure_auth, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -613,6 +655,17 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), strmov(mysql_charsets_dir, argument); charsets_dir = mysql_charsets_dir; break; + case OPT_DEFAULT_CHARSET: + default_charset_used= 1; + break; + case OPT_DELIMITER: + if (argument == disabled_my_option) + strmov(delimiter, DEFAULT_DELIMITER); + else + strmake(delimiter, argument, sizeof(delimiter) - 1); + delimiter_length= strlen(delimiter); + delimiter_str= delimiter; + break; case OPT_LOCAL_INFILE: using_opt_local_infile=1; break; @@ -646,7 +699,17 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case OPT_NOPAGER: printf("WARNING: option deprecated; use --disable-pager instead.\n"); opt_nopager= 1; + case OPT_MYSQL_PROTOCOL: + { + if ((opt_protocol = find_type(argument, &sql_protocol_typelib,0)) == + ~(ulong) 0) + { + fprintf(stderr, "Unknown option to protocol: %s\n", argument); + exit(1); + } break; + } + break; case 'A': rehash= 0; break; @@ -708,8 +771,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'W': #ifdef __WIN__ - my_free(opt_mysql_unix_port, MYF(MY_ALLOW_ZERO_PTR)); - opt_mysql_unix_port= my_strdup(MYSQL_NAMEDPIPE, MYF(0)); + opt_protocol = MYSQL_PROTOCOL_PIPE; #endif break; #include <sslopt-case.h> @@ -753,13 +815,12 @@ static int get_options(int argc, char **argv) strmov(pager, "stdout"); opt_nopager= 1; opt_outfile= 0; + opt_reconnect= 0; connect_flag= 0; /* Not in interactive mode */ } - if (default_charset) - { - if (set_default_charset_by_name(default_charset, MYF(MY_WME))) - exit(1); - } + if (!(charset_info= get_charset_by_csname(default_charset, + MY_CS_PRIMARY, MYF(MY_WME)))) + exit(1); if (argc > 1) { usage(0); @@ -784,9 +845,10 @@ static int read_lines(bool execute_commands) char *line; char in_string=0; ulong line_number=0; + bool ml_comment= 0; COMMANDS *com; status.exit_status=1; - + for (;;) { if (status.batch || !execute_commands) @@ -857,7 +919,7 @@ static int read_lines(bool execute_commands) #endif continue; } - if (add_line(glob_buffer,line,&in_string)) + if (add_line(glob_buffer,line,&in_string,&ml_comment)) break; } /* if in batch mode, send last query even if it doesn't end with \g or go */ @@ -888,14 +950,14 @@ static COMMANDS *find_command (char *name,char cmd_char) } else { - while (isspace(*name)) + while (my_isspace(charset_info,*name)) name++; - if (strchr(name,';') || strstr(name,"\\g")) + if (strstr(name, delimiter) || strstr(name, "\\g")) return ((COMMANDS *) 0); if ((end=strcont(name," \t"))) { len=(uint) (end - name); - while (isspace(*end)) + while (my_isspace(charset_info,*end)) end++; if (!*end) end=0; // no arguments to function @@ -907,7 +969,9 @@ static COMMANDS *find_command (char *name,char cmd_char) for (uint i= 0; commands[i].name; i++) { if (commands[i].func && - ((name && !my_casecmp(name,commands[i].name,len) && + ((name && + !my_strnncoll(charset_info,(uchar*)name,len, + (uchar*)commands[i].name,len) && !commands[i].name[len] && (!end || (end && commands[i].takes_params))) || !name && commands[i].cmd_char == cmd_char)) @@ -917,12 +981,12 @@ static COMMANDS *find_command (char *name,char cmd_char) } -static bool add_line(String &buffer,char *line,char *in_string) +static bool add_line(String &buffer,char *line,char *in_string, + bool *ml_comment) { uchar inchar; - char buff[80],*pos,*out; + char buff[80], *pos, *out; COMMANDS *com; - my_bool in_comment= 0; if (!line[0] && buffer.is_empty()) return 0; @@ -936,20 +1000,23 @@ static bool add_line(String &buffer,char *line,char *in_string) for (pos=out=line ; (inchar= (uchar) *pos) ; pos++) { - if (isspace(inchar) && out == line && buffer.is_empty()) + if (my_isspace(charset_info,inchar) && out == line && + buffer.is_empty()) continue; #ifdef USE_MB int l; - if (use_mb(default_charset_info) && - (l = my_ismbchar(default_charset_info, pos, strend))) { + if (use_mb(charset_info) && + (l = my_ismbchar(charset_info, pos, strend))) { while (l--) *out++ = *pos++; pos--; continue; } #endif - if (inchar == '\\') - { // mSQL or postgreSQL style command ? + if (!*ml_comment && inchar == '\\') + { + // Found possbile one character command like \c + if (!(inchar = (uchar) *++pos)) break; // readline adds one '\' if (*in_string || inchar == 'N') // \N is short for NULL @@ -960,15 +1027,20 @@ static bool add_line(String &buffer,char *line,char *in_string) } if ((com=find_command(NullS,(char) inchar))) { - const String tmp(line,(uint) (out-line)); + const String tmp(line,(uint) (out-line), charset_info); buffer.append(tmp); if ((*com->func)(&buffer,pos-1) > 0) return 1; // Quit if (com->takes_params) { - for (pos++ ; *pos && *pos != ';' ; pos++) ; // Remove parameters + for (pos++ ; + *pos && (*pos != *delimiter || + !is_prefix(pos + 1, delimiter + 1)) ; pos++) + ; // Remove parameters if (!*pos) pos--; + else + pos+= delimiter_length - 1; // Point at last delim char } out=line; } @@ -982,44 +1054,60 @@ static bool add_line(String &buffer,char *line,char *in_string) continue; } } - else if (inchar == ';' && !*in_string && !in_comment) - { // ';' is end of command + + else if (!*ml_comment && (*pos == *delimiter && + is_prefix(pos + 1, delimiter + 1)) && + !*in_string) + { + uint old_delimiter_length= delimiter_length; if (out != line) - buffer.append(line,(uint) (out-line)); // Add this line - if ((com=find_command(buffer.c_ptr(),0))) + 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) + if ((*com->func)(&buffer, buffer.c_ptr()) > 0) return 1; // Quit } else { - int error=com_go(&buffer,0); + int error= com_go(&buffer, 0); if (error) { return error < 0 ? 0 : 1; // < 0 is not fatal } } buffer.length(0); - out=line; + out= line; + pos+= old_delimiter_length - 1; } - else if (!*in_string && (inchar == '#' || - inchar == '-' && pos[1] == '-' && - isspace(pos[2]))) + else if (!*ml_comment && (!*in_string && (inchar == '#' || + inchar == '-' && pos[1] == '-' && + my_isspace(charset_info,pos[2])))) break; // comment to end of line + else if (!*in_string && inchar == '/' && *(pos+1) == '*' && + *(pos+2) != '!') + { + pos++; + *ml_comment= 1; + if (out != line) + { + buffer.append(line,(uint) (out-line)); + out=line; + } + } + else if (*ml_comment && inchar == '*' && *(pos + 1) == '/') + { + pos++; + *ml_comment= 0; + } else { // Add found char to buffer if (inchar == *in_string) - *in_string=0; - else if (!*in_string && (inchar == '\'' || inchar == '"' || inchar == '`')) - *in_string=(char) inchar; - *out++ = (char) inchar; - if (inchar == '*' && !*in_string) - { - if (pos != line && pos[-1] == '/') - in_comment= 1; - else if (in_comment && pos[1] == '/') - in_comment= 0; - } + *in_string= 0; + else if (!*ml_comment && !*in_string && + (inchar == '\'' || inchar == '"' || inchar == '`')) + *in_string= (char) inchar; + if (!*ml_comment) + *out++= (char) inchar; } } if (out != line || !buffer.is_empty()) @@ -1028,7 +1116,7 @@ static bool add_line(String &buffer,char *line,char *in_string) uint length=(uint) (out-line); if (buffer.length() + length >= buffer.alloced_length()) buffer.realloc(buffer.length()+length+IO_SIZE); - if (buffer.append(line,length)) + if (!(*ml_comment) && buffer.append(line,length)) return 1; } return 0; @@ -1040,8 +1128,8 @@ static bool add_line(String &buffer,char *line,char *in_string) #ifdef HAVE_READLINE -static char *new_command_generator(char *text, int); -static char **new_mysql_completion (char *text, int start, int end); +static char *new_command_generator(const char *text, int); +static char **new_mysql_completion (const char *text, int start, int end); /* Tell the GNU Readline library how to complete. We want to try to complete @@ -1049,8 +1137,11 @@ static char **new_mysql_completion (char *text, int start, int end); if not. */ -char **no_completion (char *text __attribute__ ((unused)), - char *word __attribute__ ((unused))) +#if defined(USE_NEW_READLINE_INTERFACE) || defined(USE_LIBEDIT_INTERFACE) +char *no_completion(const char*,int) +#else +int no_completion() +#endif { return 0; /* No filename completion */ } @@ -1061,9 +1152,19 @@ static void initialize_readline (char *name) 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; +#if defined(USE_NEW_READLINE_INTERFACE) + rl_attempted_completion_function= (rl_completion_func_t*)&new_mysql_completion; + rl_completion_entry_function= (rl_compentry_func_t*)&no_completion; +#elif defined(USE_LIBEDIT_INTERFACE) +#ifdef HAVE_LOCALE_H + setlocale(LC_ALL,""); /* so as libedit use isprint */ +#endif + rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion; + rl_completion_entry_function= (CPFunction*)&no_completion; +#else + rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion; + rl_completion_entry_function= (Function*)&no_completion; +#endif } /* @@ -1073,17 +1174,21 @@ static void initialize_readline (char *name) array of matches, or NULL if there aren't any. */ -static char **new_mysql_completion (char *text, +static char **new_mysql_completion (const char *text, int start __attribute__((unused)), int end __attribute__((unused))) { if (!status.batch && !quick) - return completion_matches(text, (CPFunction*) new_command_generator); +#if defined(USE_NEW_READLINE_INTERFACE) + return rl_completion_matches(text, new_command_generator); +#else + return completion_matches((char *)text, (CPFunction *)new_command_generator); +#endif else return (char**) 0; } -static char *new_command_generator(char *text,int state) +static char *new_command_generator(const char *text,int state) { static int textlen; char *ptr; @@ -1262,7 +1367,7 @@ You can turn off this feature to get a quicker startup with -A\n\n"); sizeof(char *) * (num_fields*2+1)))) break; - field_names[i][num_fields*2]='\0'; + field_names[i][num_fields*2]= '\0'; j=0; while ((sql_field=mysql_fetch_field(fields))) { @@ -1282,7 +1387,7 @@ You can turn off this feature to get a quicker startup with -A\n\n"); { tee_fprintf(stdout, "Didn't find any fields in table '%s'\n",table_row[0]); - field_names[i]=0; + field_names[i]= 0; } i++; } @@ -1321,7 +1426,7 @@ char *rindex(const char *s,int c) static int reconnect(void) { - if (!status.batch) + if (opt_reconnect) { put_info("No connection. Trying to reconnect...",INFO_INFO); (void) com_connect((String *) 0, 0); @@ -1338,31 +1443,160 @@ static int reconnect(void) The different commands ***************************************************************************/ +int mysql_real_query_for_lazy(const char *buf, int length) +{ + for (uint retry=0;; retry++) + { + if (!mysql_real_query(&mysql,buf,length)) + return 0; + int error= put_error(&mysql); + if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 || + !opt_reconnect) + return error; + if (reconnect()) + return error; + } +} + +int mysql_store_result_for_lazy(MYSQL_RES **result) +{ + if ((*result=mysql_store_result(&mysql))) + return 0; + + if (mysql_error(&mysql)[0]) + return put_error(&mysql); + return 0; +} + +static void print_help_item(MYSQL_ROW *cur, int num_name, int num_cat, char *last_char) +{ + char ccat= (*cur)[num_cat][0]; + if (*last_char != ccat) + { + put_info(ccat == 'Y' ? "categories :" : "topics :", INFO_INFO); + *last_char= ccat; + } + tee_fprintf(PAGER, " %s\n", (*cur)[num_name]); +} + + +static int com_server_help(String *buffer __attribute__((unused)), + char *line __attribute__((unused)), char *help_arg) +{ + MYSQL_ROW cur; + const char *server_cmd= buffer->ptr(); + char cmd_buf[100]; + MYSQL_RES *result; + MYSQL_FIELD *fields; + int error; + + if (help_arg[0] != '\'') + { + (void) strxnmov(cmd_buf, sizeof(cmd_buf), "help '", help_arg, "'", NullS); + server_cmd= cmd_buf; + } + + if (!status.batch) + { + old_buffer= *buffer; + old_buffer.copy(); + } + + if (!connected && reconnect()) + return 1; + + if ((error= mysql_real_query_for_lazy(server_cmd,strlen(server_cmd))) || + (error= mysql_store_result_for_lazy(&result))) + return error; + + if (result) + { + unsigned int num_fields= mysql_num_fields(result); + my_ulonglong num_rows= mysql_num_rows(result); + fields= mysql_fetch_fields(result); + if (num_fields==3 && num_rows==1) + { + if (!(cur= mysql_fetch_row(result))) + { + error= -1; + goto err; + } + + init_pager(); + tee_fprintf(PAGER, "Name: \'%s\'\n", cur[0]); + tee_fprintf(PAGER, "Description:\n%s", cur[1]); + if (cur[2] && *((char*)cur[2])) + tee_fprintf(PAGER, "Examples:\n%s", cur[2]); + tee_fprintf(PAGER, "\n"); + end_pager(); + } + else if (num_fields >= 2 && num_rows) + { + init_pager(); + char last_char; + + int num_name, num_cat; + LINT_INIT(num_name); + LINT_INIT(num_cat); + + if (num_fields == 2) + { + put_info("Many help items for your request exist", INFO_INFO); + put_info("For more specific request please type 'help <item>' where item is one of next", INFO_INFO); + num_name= 0; + num_cat= 1; + last_char= '_'; + } + else if ((cur= mysql_fetch_row(result))) + { + tee_fprintf(PAGER, "You asked help about help category: \"%s\"\n", cur[0]); + put_info("For a more information type 'help <item>' where item is one of the following", INFO_INFO); + num_name= 1; + num_cat= 2; + print_help_item(&cur,1,2,&last_char); + } + + while ((cur= mysql_fetch_row(result))) + print_help_item(&cur,num_name,num_cat,&last_char); + tee_fprintf(PAGER, "\n"); + end_pager(); + } + else + { + put_info("\nNothing found", INFO_INFO); + put_info("Please try to run 'help contents' for list of all accessible topics\n", INFO_INFO); + } + } + +err: + mysql_free_result(result); + return error; +} + static int -com_help (String *buffer __attribute__((unused)), - char *line __attribute__((unused))) +com_help(String *buffer __attribute__((unused)), + char *line __attribute__((unused))) { reg1 int i; + char * help_arg= strchr(line,' '); + + if (help_arg) + return com_server_help(buffer,line,help_arg+1); put_info("\nFor the complete MySQL Manual online visit:\n http://www.mysql.com/documentation\n", INFO_INFO); put_info("For info on technical support from MySQL developers visit:\n http://www.mysql.com/support\n", INFO_INFO); put_info("For info on MySQL books, utilities, consultants, etc. visit:\n http://www.mysql.com/portal\n", INFO_INFO); put_info("List of all MySQL commands:", INFO_INFO); if (!named_cmds) - put_info(" (Commands must appear first on line and end with ';')\n", - INFO_INFO); + put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO); for (i = 0; commands[i].name; i++) { if (commands[i].func) tee_fprintf(stdout, "%s\t(\\%c)\t%s\n", commands[i].name, commands[i].cmd_char, commands[i].doc); } - if (connected) - tee_fprintf(stdout, - "\nConnection id: %lu (Can be used with mysqladmin kill)\n\n", - mysql_thread_id(&mysql)); - else - tee_fprintf(stdout, "Not connected! Reconnect with 'connect'!\n\n"); + if (connected && mysql_get_server_version(&mysql) >= 40100) + put_info("\nFor server side help, type 'help all'\n", INFO_INFO); return 0; } @@ -1387,10 +1621,11 @@ com_clear(String *buffer,char *line __attribute__((unused))) static int com_go(String *buffer,char *line __attribute__((unused))) { - char buff[160],time_buff[32]; + char buff[200], time_buff[32], *pos; MYSQL_RES *result; - ulong timer; - uint error=0; + ulong timer, warnings; + uint error= 0; + int err= 0; if (!status.batch) { @@ -1412,104 +1647,106 @@ com_go(String *buffer,char *line __attribute__((unused))) if (!connected && reconnect()) { buffer->length(0); // Remove query on error - return status.batch ? 1 : -1; // Fatal error + return opt_reconnect ? -1 : 1; // Fatal error } if (verbose) (void) com_print(buffer,0); if (skip_updates && - (buffer->length() < 4 || my_sortcmp(buffer->ptr(),"SET ",4))) + (buffer->length() < 4 || my_strnncoll(charset_info, + (const uchar*)buffer->ptr(),4, + (const uchar*)"SET ",4))) { (void) put_info("Ignoring query to other database",INFO_INFO); return 0; } timer=start_timer(); - for (uint retry=0;; retry++) + + error= mysql_real_query_for_lazy(buffer->ptr(),buffer->length()); + if (error) { - 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; - } + buffer->length(0); // Remove query on error + return error; } error=0; buffer->length(0); - if (quick) + do { - if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql)) + if (quick) { - return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql)); + if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql)) + return put_error(&mysql); } - } - else - { - if (!(result=mysql_store_result(&mysql))) + else { - if (mysql_error(&mysql)[0]) - { - return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql)); - } + error= mysql_store_result_for_lazy(&result); + if (error) + return error; } - } - if (verbose >= 3 || !opt_silent) - mysql_end_timer(timer,time_buff); - else - time_buff[0]=0; - if (result) - { - if (!mysql_num_rows(result) && ! quick) + if (verbose >= 3 || !opt_silent) + mysql_end_timer(timer,time_buff); + else + time_buff[0]=0; + if (result) { - sprintf(buff,"Empty set%s",time_buff); + if (!mysql_num_rows(result) && ! quick) + { + strmov(buff, "Empty set"); + } + else + { + init_pager(); + if (opt_html) + print_table_data_html(result); + else if (opt_xml) + print_table_data_xml(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", + (long) mysql_num_rows(result), + (long) mysql_num_rows(result) == 1 ? "row" : "rows"); + end_pager(); + } } + else if (mysql_affected_rows(&mysql) == ~(ulonglong) 0) + strmov(buff,"Query OK"); else + sprintf(buff,"Query OK, %ld %s affected", + (long) mysql_affected_rows(&mysql), + (long) mysql_affected_rows(&mysql) == 1 ? "row" : "rows"); + + pos=strend(buff); + if ((warnings= mysql_warning_count(&mysql))) { - init_pager(); - if (opt_html) - print_table_data_html(result); - else if (opt_xml) - print_table_data_xml(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); - end_pager(); + *pos++= ','; + *pos++= ' '; + pos=int2str(warnings, pos, 10); + pos=strmov(pos, " warning"); + if (warnings != 1) + *pos++= 's'; } - } - 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); + strmov(pos, 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_error(&mysql); + else if (unbuffered) + fflush(stdout); + mysql_free_result(result); + } while (!(err= mysql_next_result(&mysql))); + if (err >= 1) + error= put_error(&mysql); + return error; /* New command follows */ } @@ -1582,9 +1819,8 @@ print_field_types(MYSQL_RES *result) MYSQL_FIELD *field; while ((field = mysql_fetch_field(result))) { - tee_fprintf(PAGER,"Name: '%s'\nTable: '%s'\nType: %d\nLength: %d\nMax length: %d\nIs_null: %d\nFlags: %d\nDecimals: %d\n\n", - field->name, - field->table ? "" : field->table, + tee_fprintf(PAGER,"Catalog: '%s'\nDatabase: '%s'\nTable: '%s'\nName: '%s'\nType: %d\nLength: %d\nMax length: %d\nIs_null: %d\nFlags: %d\nDecimals: %d\n\n", + field->catalog, field->db, field->table, field->name, (int) field->type, field->length, field->max_length, !IS_NOT_NULL(field->flags), @@ -1608,10 +1844,10 @@ print_table_data(MYSQL_RES *result) print_field_types(result); mysql_field_seek(result,0); } - separator.copy("+",1); + separator.copy("+",1,charset_info); while ((field = mysql_fetch_field(result))) { - uint length= column_names ? (uint) strlen(field->name) : 0; + uint length= column_names ? field->name_length : 0; if (quick) length=max(length,field->length); else @@ -1622,7 +1858,7 @@ print_table_data(MYSQL_RES *result) separator.fill(separator.length()+length+2,'-'); separator.append('+'); } - tee_puts(separator.c_ptr(), PAGER); + tee_puts(separator.c_ptr_safe(), PAGER); if (column_names) { mysql_field_seek(result,0); @@ -1738,7 +1974,7 @@ print_table_data_vertically(MYSQL_RES *result) while ((field = mysql_fetch_field(result))) { - uint length=(uint) strlen(field->name); + uint length= field->name_length; if (length > max_length) max_length= length; field->max_length=length; @@ -1803,8 +2039,9 @@ safe_put_field(const char *pos,ulong length) { #ifdef USE_MB int l; - if (use_mb(default_charset_info) && - (l = my_ismbchar(default_charset_info, pos, end))) { + if (use_mb(charset_info) && + (l = my_ismbchar(charset_info, pos, end))) + { while (l--) tee_putc(*pos++, PAGER); pos--; @@ -1864,7 +2101,7 @@ com_tee(String *buffer, char *line __attribute__((unused))) if (status.batch) return 0; - while (isspace(*line)) + while (my_isspace(charset_info,*line)) line++; if (!(param = strchr(line, ' '))) // if outfile wasn't given, use the default { @@ -1883,11 +2120,12 @@ com_tee(String *buffer, char *line __attribute__((unused))) } /* eliminate the spaces before the parameters */ - while (isspace(*param)) + while (my_isspace(charset_info,*param)) param++; end= strmake(file_name, param, sizeof(file_name) - 1); /* remove end space from command line */ - while (end > file_name && (isspace(end[-1]) || iscntrl(end[-1]))) + while (end > file_name && (my_isspace(charset_info,end[-1]) || + my_iscntrl(charset_info,end[-1]))) end--; end[0]= 0; if (end == file_name) @@ -1923,7 +2161,7 @@ com_pager(String *buffer, char *line __attribute__((unused))) if (status.batch) return 0; /* Skip space from file name */ - while (isspace(*line)) + while (my_isspace(charset_info,*line)) line++; if (!(param= strchr(line, ' '))) // if pager was not given, use the default { @@ -1939,10 +2177,11 @@ com_pager(String *buffer, char *line __attribute__((unused))) } else { - while (isspace(*param)) + while (my_isspace(charset_info,*param)) param++; end=strmake(pager_name, param, sizeof(pager_name)-1); - while (end > pager_name && (isspace(end[-1]) || iscntrl(end[-1]))) + while (end > pager_name && (my_isspace(charset_info,end[-1]) || + my_iscntrl(charset_info,end[-1]))) end--; end[0]=0; strmov(pager, pager_name); @@ -2076,23 +2315,21 @@ com_print(String *buffer,char *line __attribute__((unused))) static int com_connect(String *buffer, char *line) { - char *tmp,buff[256]; + char *tmp, buff[256]; bool save_rehash= rehash; int error; + bzero(buff, sizeof(buff)); 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"); // Skip connect command - if (tmp && (tmp=(char *) strtok(NullS," \t;"))) + strmov(buff, line); + tmp= get_arg(buff, 0); + if (tmp && *tmp) { - 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_db, MYF(MY_ALLOW_ZERO_PTR)); + current_db= my_strdup(tmp, MYF(MY_WME)); + tmp= get_arg(buff, 1); + if (tmp) { my_free(current_host,MYF(MY_ALLOW_ZERO_PTR)); current_host=my_strdup(tmp,MYF(MY_WME)); @@ -2128,15 +2365,16 @@ static int com_source(String *buffer, char *line) FILE *sql_file; /* Skip space from file name */ - while (isspace(*line)) + while (my_isspace(charset_info,*line)) line++; if (!(param = strchr(line, ' '))) // Skip command name return put_info("Usage: \\. <filename> | source <filename>", INFO_ERROR, 0); - while (isspace(*param)) + while (my_isspace(charset_info,*param)) param++; end=strmake(source_name,param,sizeof(source_name)-1); - while (end > source_name && (isspace(end[-1]) || iscntrl(end[-1]))) + while (end > source_name && (my_isspace(charset_info,end[-1]) || + my_iscntrl(charset_info,end[-1]))) end--; end[0]=0; unpack_filename(source_name,source_name); @@ -2172,23 +2410,41 @@ static int com_source(String *buffer, char *line) /* ARGSUSED */ static int +com_delimiter(String *buffer __attribute__((unused)), char *line) +{ + char buff[256], *tmp; + + strmake(buff, line, sizeof(buff) - 1); + tmp= get_arg(buff, 0); + + if (!tmp || !*tmp) + { + put_info("DELIMITER must be followed by a 'delimiter' character or string", + INFO_ERROR); + return 0; + } + strmake(delimiter, tmp, sizeof(delimiter) - 1); + delimiter_length= strlen(delimiter); + delimiter_str= delimiter; + return 0; +} + + /* 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;"); // Skip connect command - if (!tmp || !(tmp=(char *) strtok(NullS," \t;"))) + bzero(buff, sizeof(buff)); + strmov(buff, line); + tmp= get_arg(buff, 0); + if (!tmp || !*tmp) { - put_info("USE must be followed by a database name",INFO_ERROR); + put_info("USE must be followed by a database name", INFO_ERROR); return 0; } - if (!current_db || cmp_database(current_db,tmp)) + if (!current_db || cmp_database(charset_info, current_db, tmp)) { if (one_database) skip_updates= 1; @@ -2199,16 +2455,16 @@ com_use(String *buffer __attribute__((unused)), char *line) be down during query */ if (!connected && reconnect()) - return status.batch ? 1 : -1; // Fatal error + return opt_reconnect ? -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)); + return put_error(&mysql); if (reconnect()) - return status.batch ? 1 : -1; // Fatal error + return opt_reconnect ? -1 : 1; // Fatal error if (mysql_select_db(&mysql,tmp)) - return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql)); + return put_error(&mysql); } my_free(current_db,MYF(MY_ALLOW_ZERO_PTR)); current_db=my_strdup(tmp,MYF(MY_WME)); @@ -2224,6 +2480,67 @@ com_use(String *buffer __attribute__((unused)), char *line) } +/* + Gets argument from a command on the command line. If get_next_arg is + not defined, skips the command and returns the first argument. The + line is modified by adding zero to the end of the argument. If + get_next_arg is defined, then the function searches for end of string + first, after found, returns the next argument and adds zero to the + end. If you ever wish to use this feature, remember to initialize all + items in the array to zero first. +*/ + +char *get_arg(char *line, my_bool get_next_arg) +{ + char *ptr, *start; + my_bool quoted= 0, valid_arg= 0; + char qtype= 0; + + ptr= line; + if (get_next_arg) + { + for (; *ptr; ptr++) ; + if (*(ptr + 1)) + ptr++; + } + else + { + /* skip leading white spaces */ + while (my_isspace(charset_info, *ptr)) + ptr++; + if (*ptr == '\\') // short command was used + ptr+= 2; + while (*ptr &&!my_isspace(charset_info, *ptr)) // skip command + ptr++; + } + if (!*ptr) + return NullS; + while (my_isspace(charset_info, *ptr)) + ptr++; + if (*ptr == '\'' || *ptr == '\"' || *ptr == '`') + { + qtype= *ptr; + quoted= 1; + ptr++; + } + for (start=ptr ; *ptr; ptr++) + { + if (*ptr == '\\' && ptr[1]) // escaped character + { + // Remove the backslash + strmov(ptr, ptr+1); + } + else if ((!quoted && *ptr == ' ') || (quoted && *ptr == qtype)) + { + *ptr= 0; + break; + } + } + valid_arg= ptr != start; + return valid_arg ? start : NullS; +} + + static int sql_real_connect(char *host,char *database,char *user,char *password, uint silent) @@ -2239,6 +2556,8 @@ sql_real_connect(char *host,char *database,char *user,char *password, } if (opt_compress) mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS); + if (opt_secure_auth) + mysql_options(&mysql, MYSQL_SECURE_AUTH, (char *) &opt_secure_auth); if (using_opt_local_infile) mysql_options(&mysql,MYSQL_OPT_LOCAL_INFILE, (char*) &opt_local_infile); #ifdef HAVE_OPENSSL @@ -2246,6 +2565,12 @@ sql_real_connect(char *host,char *database,char *user,char *password, mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); #endif + if (opt_protocol) + mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); +#ifdef HAVE_SMEM + if (shared_memory_base_name) + mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); +#endif if (safe_updates) { char init_command[100]; @@ -2254,22 +2579,26 @@ sql_real_connect(char *host,char *database,char *user,char *password, select_limit,max_join_size); mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command); } + if (default_charset_used) + mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); if (!mysql_real_connect(&mysql, host, user, password, database, opt_mysql_port, opt_mysql_unix_port, - connect_flag)) + connect_flag | CLIENT_MULTI_STATEMENTS)) { 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) put_error(&mysql); (void) fflush(stdout); return ignore_errors ? -1 : 1; // Abort } return -1; // Retryable } connected=1; +#ifndef EMBEDDED_LIBRARY mysql.reconnect=info_flag ? 1 : 0; // We want to know if this happens +#endif #ifdef HAVE_READLINE build_completion_hash(rehash, 1); #endif @@ -2358,18 +2687,21 @@ com_status(String *buffer __attribute__((unused)), tee_fprintf(stdout, "Current pager:\t\t%s\n", pager); tee_fprintf(stdout, "Using outfile:\t\t'%s'\n", opt_outfile ? outfile : ""); #endif + tee_fprintf(stdout, "Using delimiter:\t%s\n", delimiter); tee_fprintf(stdout, "Server version:\t\t%s\n", mysql_get_server_info(&mysql)); tee_fprintf(stdout, "Protocol version:\t%d\n", mysql_get_proto_info(&mysql)); tee_fprintf(stdout, "Connection:\t\t%s\n", mysql_get_host_info(&mysql)); tee_fprintf(stdout, "Client characterset:\t%s\n", - default_charset_info->name); + charset_info->name); tee_fprintf(stdout, "Server characterset:\t%s\n", mysql.charset->name); +#ifndef EMBEDDED_LIBRARY if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || ! mysql.unix_socket) tee_fprintf(stdout, "TCP port:\t\t%d\n", mysql.port); else tee_fprintf(stdout, "UNIX socket:\t\t%s\n", mysql.unix_socket); if (mysql.net.compress) tee_fprintf(stdout, "Protocol:\t\tCompressed\n"); +#endif if ((status=mysql_stat(&mysql)) && !mysql_error(&mysql)[0]) { @@ -2408,7 +2740,7 @@ select_limit, max_join_size); static int -put_info(const char *str,INFO_TYPE info_type,uint error) +put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate) { FILE *file= (info_type == INFO_ERROR ? stderr : stdout); static int inited=0; @@ -2453,7 +2785,12 @@ put_info(const char *str,INFO_TYPE info_type,uint error) putchar('\007'); /* This should make a bell */ vidattr(A_STANDOUT); if (error) - (void) tee_fprintf(file, "ERROR %d: ", error); + { + if (sqlstate) + (void) tee_fprintf(file, "ERROR %d (%s): ", error, sqlstate); + else + (void) tee_fprintf(file, "ERROR %d: ", error); + } else tee_puts("ERROR: ", file); } @@ -2468,11 +2805,19 @@ put_info(const char *str,INFO_TYPE info_type,uint error) } +static int +put_error(MYSQL *mysql) +{ + return put_info(mysql_error(mysql), INFO_ERROR, mysql_errno(mysql), + mysql_sqlstate(mysql)); +} + + static void remove_cntrl(String &buffer) { char *start,*end; end=(start=(char*) buffer.ptr())+buffer.length(); - while (start < end && !isgraph(end[-1])) + while (start < end && !my_isgraph(charset_info,end[-1])) end--; buffer.length((uint) (end-start)); } @@ -2638,19 +2983,21 @@ static const char* construct_prompt() break; } case 'p': +#ifndef EMBEDDED_LIBRARY if (!connected) { processed_prompt.append("not_connected"); break; } - if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || ! - mysql.unix_socket) + if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || + !mysql.unix_socket) add_int_to_prompt(mysql.port); else { char *pos=strrchr(mysql.unix_socket,'/'); - processed_prompt.append(pos ? pos+1 : mysql.unix_socket); + processed_prompt.append(pos ? pos+1 : mysql.unix_socket); } +#endif break; case 'U': if (!full_username) diff --git a/client/mysqladmin.c b/client/mysqladmin.c index 95bc17e880b..f263d321a7b 100644 --- a/client/mysqladmin.c +++ b/client/mysqladmin.c @@ -23,6 +23,7 @@ #include <my_pthread.h> /* because of signal() */ #endif #include <sys/stat.h> +#include <mysql.h> #define ADMIN_VERSION "8.40" #define MAX_MYSQL_VAR 256 @@ -42,6 +43,11 @@ static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations, static ulong opt_connect_timeout, opt_shutdown_timeout; static my_string unix_port=0; +#ifdef HAVE_SMEM +static char *shared_memory_base_name=0; +#endif +static uint opt_protocol=0; + /* When using extended-status relatively, ex_val_max_len is the estimated maximum length for any relative value printed by extended-status. The @@ -78,16 +84,16 @@ 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, +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 + 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, ADMIN_OLD_PASSWORD }; static const char *command_names[]= { "create", "drop", "shutdown", @@ -96,8 +102,8 @@ static const char *command_names[]= { "debug", "variables", "flush-logs", "flush-hosts", "flush-tables", "password", "ping", "extended-status", "flush-status", - "flush-privileges", "start-slave", "stop-slave", - "flush-threads", + "flush-privileges", "start-slave", "stop-slave", + "flush-threads","old-password", NullS }; @@ -107,16 +113,16 @@ static TYPELIB command_typelib= static struct my_option my_long_options[] = { {"count", 'c', - "Number of iterations to make. This works with -i (--sleep) only", + "Number of iterations to make. This works with -i (--sleep) only.", (gptr*) &nr_iterations, (gptr*) &nr_iterations, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'", + {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"force", 'f', "Don't ask for confirmation on drop database; with multiple commands, continue even if an error occurs.", (gptr*) &option_force, (gptr*) &option_force, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"compress", 'C', "Use compression in server/client protocol", + {"compress", 'C', "Use compression in server/client protocol.", (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"character-sets-dir", OPT_CHARSETS_DIR, @@ -124,7 +130,7 @@ static struct my_option my_long_options[] = (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"host", 'h', "Connect to host", (gptr*) &host, (gptr*) &host, 0, GET_STR, + {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to use when connecting to server. If password is not given it's asked from the tty.", @@ -135,6 +141,8 @@ static struct my_option my_long_options[] = #endif {"port", 'P', "Port number to use for connection.", (gptr*) &tcp_port, (gptr*) &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"relative", 'r', "Show difference between current and previous values when used with -i. Currently works only with extended-status.", (gptr*) &opt_relative, (gptr*) &opt_relative, 0, GET_BOOL, NO_ARG, 0, 0, 0, @@ -142,7 +150,12 @@ static struct my_option my_long_options[] = {"set-variable", 'O', "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"silent", 's', "Silently exit if one can't connect to server", +#ifdef HAVE_SMEM + {"shared_memory_base_name", OPT_SHARED_MEMORY_BASE_NAME, + "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif + {"silent", 's', "Silently exit if one can't connect to server.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", (gptr*) &unix_port, (gptr*) &unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, @@ -157,13 +170,13 @@ static struct my_option my_long_options[] = #endif {"verbose", 'v', "Write more information.", (gptr*) &opt_verbose, (gptr*) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"version", 'V', "Output version information and exit", 0, 0, 0, GET_NO_ARG, + {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"vertical", 'E', + {"vertical", 'E', "Print output vertically. Is similar to --relative, but prints output vertically.", (gptr*) &opt_vertical, (gptr*) &opt_vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"wait", 'w', "Wait and retry if connection is down", 0, 0, 0, GET_UINT, + {"wait", 'w', "Wait and retry if connection is down.", 0, 0, 0, GET_UINT, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"connect_timeout", OPT_CONNECT_TIMEOUT, "", (gptr*) &opt_connect_timeout, (gptr*) &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 3600*12, 0, @@ -205,7 +218,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'W': #ifdef __WIN__ - unix_port=MYSQL_NAMEDPIPE; + opt_protocol = MYSQL_PROTOCOL_PIPE; #endif break; case '#': @@ -234,6 +247,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), charsets_dir = argument; #endif break; + case OPT_MYSQL_PROTOCOL: + { + if ((opt_protocol = find_type(argument, &sql_protocol_typelib,0)) == ~(ulong) 0) + { + fprintf(stderr, "Unknown option to protocol: %s\n", argument); + exit(1); + } + break; + } } if (error) { @@ -284,6 +306,12 @@ int main(int argc,char *argv[]) mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); #endif + if (opt_protocol) + mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); +#ifdef HAVE_SMEM + if (shared_memory_base_name) + mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); +#endif if (sql_connect(&mysql, option_wait)) error = 1; else @@ -326,6 +354,9 @@ int main(int argc,char *argv[]) } my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); my_free(user,MYF(MY_ALLOW_ZERO_PTR)); +#ifdef HAVE_SMEM + my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); +#endif free_defaults(save_argv); my_end(0); exit(error ? 1 : 0); @@ -386,7 +417,7 @@ static my_bool sql_connect(MYSQL *mysql, uint wait) 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; @@ -401,7 +432,7 @@ static my_bool sql_connect(MYSQL *mysql, uint wait) } else { - putc('.',stderr); + putc('.',stderr); (void) fflush(stderr); } } @@ -419,6 +450,7 @@ static my_bool sql_connect(MYSQL *mysql, uint wait) static int execute_commands(MYSQL *mysql,int argc, char **argv) { const char *status; + struct rand_struct rand_st; for (; argc > 0 ; argv++,argc--) { @@ -488,7 +520,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) } case ADMIN_FLUSH_PRIVILEGES: case ADMIN_RELOAD: - if (mysql_refresh(mysql,REFRESH_GRANT) < 0) + if (mysql_query(mysql,"flush privileges")) { my_printf_error(0,"reload failed; error: '%s'",MYF(ME_BELL), mysql_error(mysql)); @@ -499,7 +531,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) if (mysql_refresh(mysql, (uint) ~(REFRESH_GRANT | REFRESH_STATUS | REFRESH_READ_LOCK | REFRESH_SLAVE | - REFRESH_MASTER)) < 0) + REFRESH_MASTER))) { my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL), mysql_error(mysql)); @@ -507,7 +539,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) } break; case ADMIN_FLUSH_THREADS: - if (mysql_refresh(mysql,(uint) REFRESH_THREADS) < 0) + if (mysql_refresh(mysql,(uint) REFRESH_THREADS)) { my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL), mysql_error(mysql)); @@ -630,7 +662,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) MYSQL_RES *res; MYSQL_ROW row; uint rownr = 0; - void (*func) (MYSQL_RES*, MYSQL_ROW, uint); + void (*func) (MYSQL_RES*, MYSQL_ROW, uint); new_line = 1; if (mysql_query(mysql, "show status") || @@ -694,7 +726,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) } case ADMIN_FLUSH_HOSTS: { - if (mysql_refresh(mysql,REFRESH_HOSTS)) + if (mysql_query(mysql,"flush hosts")) { my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL), mysql_error(mysql)); @@ -704,7 +736,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) } case ADMIN_FLUSH_TABLES: { - if (mysql_refresh(mysql,REFRESH_TABLES)) + if (mysql_query(mysql,"flush tables")) { my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL), mysql_error(mysql)); @@ -714,7 +746,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) } case ADMIN_FLUSH_STATUS: { - if (mysql_refresh(mysql,REFRESH_STATUS)) + if (mysql_query(mysql,"flush status")) { my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL), mysql_error(mysql)); @@ -722,9 +754,14 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) } break; } + case ADMIN_OLD_PASSWORD: case ADMIN_PASSWORD: { - char buff[128],crypted_pw[33]; + char buff[128],crypted_pw[64]; + time_t start_time; + /* Do initialization the same way as we do in mysqld */ + start_time=time((time_t*) 0); + randominit(&rand_st,(ulong) start_time,(ulong) start_time/2); if (argc < 2) { @@ -732,7 +769,12 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) return 1; } if (argv[1][0]) - make_scrambled_password(crypted_pw,argv[1]); + { + if (find_type(argv[0], &command_typelib, 2) == ADMIN_OLD_PASSWORD) + make_scrambled_password_323(crypted_pw, argv[1]); + else + 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); @@ -754,7 +796,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) } case ADMIN_START_SLAVE: - if (mysql_query(mysql, "SLAVE START")) + if (mysql_query(mysql, "START SLAVE")) { my_printf_error(0, "Error starting slave: %s", MYF(ME_BELL), mysql_error(mysql)); @@ -764,7 +806,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) puts("Slave started"); break; case ADMIN_STOP_SLAVE: - if (mysql_query(mysql, "SLAVE STOP")) + if (mysql_query(mysql, "STOP SLAVE")) { my_printf_error(0, "Error stopping slave: %s", MYF(ME_BELL), mysql_error(mysql)); @@ -837,7 +879,8 @@ static void usage(void) kill id,id,... Kill mysql threads"); #if MYSQL_VERSION_ID >= 32200 puts("\ - password new-password Change old password to new-password"); + password new-password Change old password to new-password, MySQL 4.1 hashing.\n\ + old-password new-password Change old password to new-password in old format.\n"); #endif puts("\ ping Check if mysqld is alive\n\ @@ -995,7 +1038,7 @@ static void print_relative_row_vert(MYSQL_RES *result __attribute__((unused)), putchar('|'); tmp = cur[1] ? strtoull(cur[1], NULL, 10) : (ulonglong) 0; - printf(" %-*s|", ex_val_max_len[row] + 1, + 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 */ diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 34b7ae11f74..35f0db76ad6 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2001 MySQL AB +/* Copyright (C) 2001-2003 MySQL 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 @@ -34,6 +34,7 @@ ulong server_id = 0; ulong bytes_sent = 0L, bytes_received = 0L; ulong mysqld_net_retry_count = 10L; uint test_flags = 0; +static uint opt_protocol= 0; static FILE *result_file; @@ -56,7 +57,6 @@ static char* pass = 0; static ulonglong position = 0; static short binlog_flags = 0; static MYSQL* mysql = NULL; - static const char* dirname_for_local_load= 0; static void dump_local_log_entries(const char* logname); @@ -234,6 +234,10 @@ static struct my_option my_long_options[] = {"position", 'j', "Start reading the binlog at position N.", (gptr*) &position, (gptr*) &position, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"protocol", OPT_MYSQL_PROTOCOL, + "The protocol of connection (tcp,socket,pipe,memory).", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"result-file", 'r', "Direct output to a given file.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"read-from-remote-server", 'R', "Read binary logs from a MySQL server", @@ -286,7 +290,7 @@ static void die(const char* fmt, ...) static void print_version() { - printf("%s Ver 2.4 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE); + printf("%s Ver 2.5 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE); } @@ -370,6 +374,17 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'R': remote_opt= 1; break; + case OPT_MYSQL_PROTOCOL: + { + if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) == + ~(ulong) 0) + { + fprintf(stderr, "Unknown option to protocol: %s\n", argument); + exit(1); + } + break; + } + break; case 'V': print_version(); exit(0); @@ -399,9 +414,11 @@ static int parse_args(int *argc, char*** argv) static MYSQL* safe_connect() { MYSQL *local_mysql = mysql_init(NULL); - if(!local_mysql) + if (!local_mysql) die("Failed on mysql_init"); + if (opt_protocol) + mysql_options(local_mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol); if (!mysql_real_connect(local_mysql, host, user, pass, 0, port, sock, 0)) die("failed on connect: %s", mysql_error(local_mysql)); @@ -687,75 +704,6 @@ Create_file event for file_id: %u\n",exv->file_id); end_io_cache(file); } -#if MYSQL_VERSION_ID < 40101 - -typedef struct st_my_tmpdir -{ - char **list; - uint cur, max; -} MY_TMPDIR; - -#if defined( __WIN__) || defined(OS2) -#define DELIM ';' -#else -#define DELIM ':' -#endif - -my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist) -{ - char *end, *copy; - char buff[FN_REFLEN]; - DYNAMIC_ARRAY t_arr; - if (my_init_dynamic_array(&t_arr, sizeof(char*), 1, 5)) - return TRUE; - if (!pathlist || !pathlist[0]) - { - /* Get default temporary directory */ - pathlist=getenv("TMPDIR"); /* Use this if possible */ -#if defined( __WIN__) || defined(OS2) - if (!pathlist) - pathlist=getenv("TEMP"); - if (!pathlist) - pathlist=getenv("TMP"); -#endif - if (!pathlist || !pathlist[0]) - pathlist=(char*) P_tmpdir; - } - do - { - end=strcend(pathlist, DELIM); - convert_dirname(buff, pathlist, end); - if (!(copy=my_strdup(buff, MYF(MY_WME)))) - return TRUE; - if (insert_dynamic(&t_arr, (gptr)©)) - return TRUE; - pathlist=end+1; - } - while (*end); - freeze_size(&t_arr); - tmpdir->list=(char **)t_arr.buffer; - tmpdir->max=t_arr.elements-1; - tmpdir->cur=0; - return FALSE; -} - -char *my_tmpdir(MY_TMPDIR *tmpdir) -{ - char *dir; - dir=tmpdir->list[tmpdir->cur]; - tmpdir->cur= (tmpdir->cur == tmpdir->max) ? 0 : tmpdir->cur+1; - return dir; -} - -void free_tmpdir(MY_TMPDIR *tmpdir) -{ - uint i; - for (i=0; i<=tmpdir->max; i++) - my_free(tmpdir->list[i], MYF(0)); - my_free((gptr)tmpdir->list, MYF(0)); -} - -#endif int main(int argc, char** argv) { @@ -791,7 +739,6 @@ int main(int argc, char** argv) while (--argc >= 0) dump_log_entries(*(argv++)); - if (tmpdir.list) free_tmpdir(&tmpdir); if (result_file != stdout) diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 3261ec1577d..1768d948373 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -37,10 +37,16 @@ static my_bool opt_alldbs = 0, opt_check_only_changed = 0, opt_extended = 0, tty_password = 0, opt_frm = 0; static uint verbose = 0, opt_mysql_port=0; static my_string opt_mysql_unix_port = 0; -static char *opt_password = 0, *current_user = 0, *default_charset = 0, - *current_host = 0; +static char *opt_password = 0, *current_user = 0, + *default_charset = (char *)MYSQL_DEFAULT_CHARSET_NAME, + *current_host = 0; static int first_error = 0; DYNAMIC_ARRAY tables4repair; +#ifdef HAVE_SMEM +static char *shared_memory_base_name=0; +#endif +static uint opt_protocol=0; +static CHARSET_INFO *charset_info= &my_charset_latin1; enum operations {DO_CHECK, DO_REPAIR, DO_ANALYZE, DO_OPTIMIZE}; @@ -61,9 +67,9 @@ static struct my_option my_long_options[] = (gptr*) &opt_auto_repair, (gptr*) &opt_auto_repair, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory where character sets are", (gptr*) &charsets_dir, + "Directory where character sets are.", (gptr*) &charsets_dir, (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"check", 'c', "Check table for errors", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, + {"check", 'c', "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"check-only-changed", 'C', "Check only tables that have changed since last check or haven't been closed properly.", @@ -75,12 +81,12 @@ static struct my_option my_long_options[] = "To check several databases. Note the difference in usage; In this case no tables are given. All name arguments are regarded as databasenames.", (gptr*) &opt_databases, (gptr*) &opt_databases, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'", + {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"default-character-set", OPT_DEFAULT_CHARSET, - "Set the default character set", (gptr*) &default_charset, + "Set the default character set.", (gptr*) &default_charset, (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"fast",'F', "Check only tables that haven't been closed properly", + {"fast",'F', "Check only tables that haven't been closed properly.", (gptr*) &opt_fast, (gptr*) &opt_fast, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"force", 'f', "Continue even if we get an sql-error.", @@ -109,6 +115,8 @@ static struct my_option my_long_options[] = {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, + {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"quick", 'q', "If you are using this option with CHECK TABLE, it prevents the check from scanning the rows to check for wrong links. This is the fastest check. If you are using this option with REPAIR TABLE, it will try to repair only the index tree. This is the fastest repair method for a table.", (gptr*) &opt_quick, (gptr*) &opt_quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, @@ -116,6 +124,11 @@ static struct my_option my_long_options[] = {"repair", 'r', "Can fix almost anything except unique keys that aren't unique.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_SMEM + {"shared_memory_base_name", OPT_SHARED_MEMORY_BASE_NAME, + "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"silent", 's', "Print only error messages.", (gptr*) &opt_silent, (gptr*) &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", @@ -238,7 +251,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'W': #ifdef __WIN__ - opt_mysql_unix_port = MYSQL_NAMEDPIPE; + opt_protocol = MYSQL_PROTOCOL_PIPE; #endif break; case '#': @@ -252,6 +265,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), verbose++; break; case 'V': print_version(); exit(0); + case OPT_MYSQL_PROTOCOL: + { + if ((opt_protocol = find_type(argument, &sql_protocol_typelib,0)) == ~(ulong) 0) + { + fprintf(stderr, "Unknown option to protocol: %s\n", argument); + exit(1); + } + break; + } } return 0; } @@ -287,11 +309,11 @@ static int get_options(int *argc, char ***argv) else what_to_do = DO_CHECK; } - if (default_charset) - { - if (set_default_charset_by_name(default_charset, MYF(MY_WME))) + + /* TODO: This variable is not yet used */ + if (!(charset_info= get_charset_by_csname(default_charset, + MY_CS_PRIMARY, MYF(MY_WME)))) exit(1); - } if (*argc > 0 && opt_alldbs) { printf("You should give only options, no arguments at all, with option\n"); @@ -582,6 +604,12 @@ static int dbConnect(char *host, char *user, char *passwd) mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); #endif + if (opt_protocol) + mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); +#ifdef HAVE_SMEM + if (shared_memory_base_name) + mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); +#endif if (!(sock = mysql_real_connect(&mysql_connection, host, user, passwd, NULL, opt_mysql_port, opt_mysql_unix_port, 0))) { @@ -669,6 +697,9 @@ int main(int argc, char **argv) if (opt_auto_repair) delete_dynamic(&tables4repair); my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); +#ifdef HAVE_SMEM + my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); +#endif my_end(0); return(first_error!=0); } /* main */ diff --git a/client/mysqldump.c b/client/mysqldump.c index 489869f6c3d..d5c80b31141 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -30,13 +30,14 @@ ** master/autocommit code by Brian Aker <brian@tangent.org> ** SSL by ** Andrei Errapart <andreie@no.spam.ee> -** Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee> +** Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee> ** XML by Gary Huntress <ghuntress@mediaone.net> 10/10/01, cleaned up ** and adapted to mysqldump 05/11/01 by Jani Tolonen ** Added --single-transaction option 06/06/2002 by Peter Zaitsev +** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov */ -#define DUMP_VERSION "9.10" +#define DUMP_VERSION "10.4" #include <my_global.h> #include <my_sys.h> @@ -69,28 +70,53 @@ static char *add_load_option(char *ptr, const char *object, const char *statement); +static ulong find_set(TYPELIB *lib, const char *x, uint length, + char **err_pos, uint *err_len); 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, - opt_autocommit=0,opt_master_data,opt_disable_keys=0,opt_xml=0, +static my_bool verbose=0,tFlag=0,cFlag=0,dFlag=0,quick= 1, extended_insert= 1, + lock_tables=1,ignore_errors=0,flush_logs=0,replace=0, + ignore=0,opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0, + opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0, + opt_alldbs=0,opt_create_db=0,opt_first_slave=0,opt_set_names=0, + opt_autocommit=0,opt_master_data,opt_disable_keys=1,opt_xml=0, opt_delete_master_logs=0, tty_password=0, opt_single_transaction=0, opt_comments= 0; static MYSQL mysql_connection,*sock=0; static char insert_pat[12 * 1024],*opt_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; + *where=0, + *opt_compatible_mode_str= 0, + *err_ptr= 0; +#ifdef HAVE_CHARSET_utf8 +static char *default_charset= (char*) "utf8"; +#else +static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; +#endif +static ulong opt_compatible_mode= 0; +static uint opt_mysql_port= 0, err_len= 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> FILE *md_result_file; +#ifdef HAVE_SMEM +static char *shared_memory_base_name=0; +#endif +static uint opt_protocol= 0; +static CHARSET_INFO *charset_info= &my_charset_latin1; + +const char *compatible_mode_names[]= +{ + "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2", + "SAPDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", + NullS +}; +TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1, + "", compatible_mode_names}; + static struct my_option my_long_options[] = { @@ -99,20 +125,24 @@ static struct my_option my_long_options[] = (gptr*) &opt_alldbs, (gptr*) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"all", 'a', "Include all MySQL specific create options.", - (gptr*) &create_options, (gptr*) &create_options, 0, GET_BOOL, NO_ARG, 0, + (gptr*) &create_options, (gptr*) &create_options, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"add-drop-table", OPT_DROP, "Add a 'drop table' before each create.", - (gptr*) &opt_drop, (gptr*) &opt_drop, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, + (gptr*) &opt_drop, (gptr*) &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"add-locks", OPT_LOCKS, "Add locks around insert statements.", - (gptr*) &opt_lock, (gptr*) &opt_lock, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, + (gptr*) &opt_lock, (gptr*) &opt_lock, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"allow-keywords", OPT_KEYWORDS, "Allow creation of column names that are keywords.", (gptr*) &opt_keywords, (gptr*) &opt_keywords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory where character sets are", (gptr*) &charsets_dir, + "Directory where character sets are.", (gptr*) &charsets_dir, (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"compatible", OPT_COMPATIBLE, + "Change the dump to be compatible with a given mode. By default tables are dumped without any restrictions. Legal modes are: mysql323, mysql40, postgresql, oracle, mssql, db2, sapdb, no_key_options, no_table_options, no_field_options. One can use several modes separated by commas. Note: Requires MySQL server version 4.1.0 or higher. This option does a no operation on earlier server versions.", + (gptr*) &opt_compatible_mode_str, (gptr*) &opt_compatible_mode_str, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"complete-insert", 'c', "Use complete insert statements.", (gptr*) &cFlag, (gptr*) &cFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"compress", 'C', "Use compression in server/client protocol.", @@ -135,11 +165,11 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"disable-keys", 'K', "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER TABLE tb_name ENABLE KEYS */; will be put in the output.", (gptr*) &opt_disable_keys, - (gptr*) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + (gptr*) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"extended-insert", 'e', "Allows utilization of the new, much faster INSERT syntax.", (gptr*) &extended_insert, (gptr*) &extended_insert, 0, GET_BOOL, NO_ARG, - 0, 0, 0, 0, 0, 0}, + 1, 0, 0, 0, 0, 0}, {"fields-terminated-by", OPT_FTB, "Fields in the textfile are terminated by ...", (gptr*) &fields_terminated, (gptr*) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -168,7 +198,7 @@ static struct my_option my_long_options[] = (gptr*) &lines_terminated, (gptr*) &lines_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"lock-tables", 'l', "Lock all tables for read.", (gptr*) &lock_tables, - (gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + (gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"master-data", OPT_MASTER_DATA, "This will cause the master position and filename to be appended to your output. This will automagically enable --first-slave.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -178,40 +208,54 @@ static struct my_option my_long_options[] = 0, 0, 0, 0, 0, 0}, {"single-transaction", OPT_TRANSACTION, "Dump all tables in single transaction to get consistent snapshot. Mutually exclusive with --lock-tables.", - (gptr*) &opt_single_transaction, (gptr*) &opt_single_transaction, 0, GET_BOOL, NO_ARG, - 0, 0, 0, 0, 0, 0}, + (gptr*) &opt_single_transaction, (gptr*) &opt_single_transaction, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"no-create-db", 'n', - "'CREATE DATABASE /*!32312 IF NOT EXISTS*/ db_name;' will not be put in the output. The above line will be added otherwise, if --databases or --all-databases option was given.}", + "'CREATE DATABASE /*!32312 IF NOT EXISTS*/ db_name;' will not be put in the output. The above line will be added otherwise, if --databases or --all-databases option was given.}.", (gptr*) &opt_create_db, (gptr*) &opt_create_db, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"no-create-info", 't', "Don't write table creation info.", (gptr*) &tFlag, (gptr*) &tFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"no-data", 'd', "No row information.", (gptr*) &dFlag, (gptr*) &dFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"no-set-names", 'N', + "'SET NAMES charset_name' will not be put in the output.", + (gptr*) &opt_set_names, (gptr*) &opt_set_names, 0, GET_BOOL, NO_ARG, 0, 0, + 0, 0, 0, 0}, {"set-variable", 'O', "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"opt", OPT_OPTIMIZE, - "Same as --add-drop-table --add-locks --all --quick --extended-insert --lock-tables --disable-keys", + "Same as --add-drop-table --add-locks --all --quick --extended-insert --lock-tables --disable-keys. Enabled by default, disable with --skip-opt.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to use when connecting to server. If password is not given it's solicited on the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #ifdef __WIN__ - {"pipe", 'W', "Use named pipes to connect to server", 0, 0, 0, GET_NO_ARG, + {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, + {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"quick", 'q', "Don't buffer query, dump directly to stdout.", - (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"quote-names",'Q', "Quote table and column names with a `", + (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"quote-names",'Q', "Quote table and column names with backticks (`).", (gptr*) &opt_quoted, (gptr*) &opt_quoted, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"result-file", 'r', "Direct output to a given file. This option should be used in MSDOS, because it prevents new line '\\n' from being converted to '\\r\\n' (carriage return + line feed).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_SMEM + {"shared_memory_base_name", OPT_SHARED_MEMORY_BASE_NAME, + "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif + {"skip-opt", OPT_SKIP_OPTIMIZATION, + "Disable --opt. Disables --add-locks, --all, --quick, --extended-insert, --lock-tables and --disable-keys.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -261,7 +305,6 @@ static int init_dumping(char *); static int dump_databases(char **); static int dump_all_databases(); static char *quote_name(const char *name, char *buff, my_bool force); -static void print_quoted_xml(FILE *output, char *fname, char *str, uint len); static const char *check_if_ignore_table(const char *table_name); @@ -304,8 +347,8 @@ static void write_header(FILE *sql_file, char *db_name) { if (opt_xml) { - fprintf(sql_file,"<?xml version=\"1.0\"?>\n"); - fprintf(sql_file,"<mysqldump>\n"); + fputs("<?xml version=\"1.0\"?>\n", sql_file); + fputs("<mysqldump>\n", sql_file); } else if (opt_comments) { @@ -316,18 +359,36 @@ static void write_header(FILE *sql_file, char *db_name) sql_file); fprintf(sql_file, "-- Server version\t%s\n", mysql_get_server_info(&mysql_connection)); + if (!opt_set_names) + fprintf(sql_file,"\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT, CHARACTER_SET_CLIENT=%s */;\n",default_charset); + fprintf(md_result_file,"\ +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n\ +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n\ +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=NO_AUTO_VALUE_ON_ZERO */;\n\ +"); } return; } /* write_header */ + static void write_footer(FILE *sql_file) { if (opt_xml) - fprintf(sql_file,"</mysqldump>"); + fputs("</mysqldump>", sql_file); + else + { + fprintf(md_result_file,"\n\ +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n\ +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n\ +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n\ +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n\ +"); + } fputs("\n", sql_file); } /* write_footer */ + static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) @@ -361,7 +422,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'W': #ifdef __WIN__ - opt_mysql_unix_port=MYSQL_NAMEDPIPE; + opt_protocol = MYSQL_PROTOCOL_PIPE; #endif break; case 'T': @@ -374,25 +435,57 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'V': print_version(); exit(0); case 'X': opt_xml = 1; - opt_disable_keys=0; + extended_insert= opt_drop= opt_lock= + opt_disable_keys= opt_autocommit= opt_create_db= 0; break; case 'I': case '?': usage(); exit(0); case (int) OPT_OPTIMIZE: - extended_insert=opt_drop=opt_lock=quick=create_options=opt_disable_keys= - lock_tables=1; + extended_insert= opt_drop= opt_lock= quick= create_options= + opt_disable_keys= lock_tables= 1; if (opt_single_transaction) lock_tables=0; break; + case (int) OPT_SKIP_OPTIMIZATION: + extended_insert= opt_drop= opt_lock= quick= create_options= + opt_disable_keys= lock_tables= 0; + break; case (int) OPT_TABLES: opt_databases=0; break; + case (int) OPT_COMPATIBLE: + { + char buff[255]; + + opt_quoted= 1; + opt_set_names= 1; + opt_compatible_mode_str= argument; + opt_compatible_mode= find_set(&compatible_mode_typelib, + argument, strlen(argument), + &err_ptr, &err_len); + if (err_len) + { + strmake(buff, err_ptr, min(sizeof(buff), err_len)); + fprintf(stderr, "Invalid mode to --compatible: %s\n", buff); + exit(1); + } + break; + } + case (int) OPT_MYSQL_PROTOCOL: + { + if ((opt_protocol= find_type(argument, &sql_protocol_typelib, 0)) + == ~(ulong) 0) + { + fprintf(stderr, "Unknown option to protocol: %s\n", argument); + exit(1); + } + break; + } } return 0; } - static int get_options(int *argc, char ***argv) { int ho_error; @@ -412,13 +505,8 @@ static int get_options(int *argc, char ***argv) "%s: You must use option --tab with --fields-...\n", my_progname); return(1); } - - if (opt_single_transaction && lock_tables) - { - fprintf(stderr, "%s: You can't use --lock-tables and --single-transaction at the same time.\n", my_progname); - return(1); - } - + if (opt_single_transaction) + lock_tables= 0; if (enclosed && opt_enclosed) { fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname); @@ -436,11 +524,9 @@ static int get_options(int *argc, char ***argv) my_progname); return(1); } - if (default_charset) - { - if (set_default_charset_by_name(default_charset, MYF(MY_WME))) - exit(1); - } + if (!(charset_info= get_charset_by_csname(default_charset, + MY_CS_PRIMARY, MYF(MY_WME)))) + exit(1); if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs)) { short_usage(); @@ -497,6 +583,14 @@ static int dbConnect(char *host, char *user,char *passwd) mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); #endif + if (opt_protocol) + mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); +#ifdef HAVE_SMEM + if (shared_memory_base_name) + mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); +#endif + if (!opt_set_names) + mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset); if (!(sock= mysql_real_connect(&mysql_connection,host,user,passwd, NULL,opt_mysql_port,opt_mysql_unix_port, 0))) @@ -541,13 +635,14 @@ static my_bool test_if_special_chars(const char *str) { #if MYSQL_VERSION_ID >= 32300 for ( ; *str ; str++) - if (!isvar(*str) && *str != '$') + if (!my_isvar(charset_info,*str) && *str != '$') return 1; #endif return 0; } /* test_if_special_chars */ + static char *quote_name(const char *name, char *buff, my_bool force) { char *to= buff; @@ -584,6 +679,119 @@ static char *quote_for_like(const char *name, char *buff) /* + Quote and print a string. + + SYNOPSIS + print_quoted_xml() + output - output file + str - string to print + len - its length + + DESCRIPTION + Quote '<' '>' '&' '\"' singns and print a string to the xml_file. +*/ + +static void print_quoted_xml(FILE *xml_file, const char *str, ulong len) +{ + const char *end; + + for (end= str + len; str != end; str++) + { + switch (*str) { + case '<': + fputs("<", xml_file); + break; + case '>': + fputs(">", xml_file); + break; + case '&': + fputs("&", xml_file); + break; + case '\"': + fputs(""", xml_file); + break; + default: + fputc(*str, xml_file); + break; + } + } +} + + +/* + Print xml tag with one attribute. + + SYNOPSIS + print_xml_tag1() + xml_file - output file + sbeg - line beginning + stag_atr - tag and attribute + sval - value of attribute + send - line ending + + DESCRIPTION + Print tag with one attribute to the xml_file. Format is: + sbeg<stag_atr="sval">send + NOTE + sval MUST be a NULL terminated string. + sval string will be qouted before output. +*/ + +static void print_xml_tag1(FILE * xml_file, const char* sbeg, + const char* stag_atr, const char* sval, + const char* send) +{ + fputs(sbeg, xml_file); + fputs("<", xml_file); + fputs(stag_atr, xml_file); + fputs("\"", xml_file); + print_quoted_xml(xml_file, sval, strlen(sval)); + fputs("\">", xml_file); + fputs(send, xml_file); +} + + +/* + Print xml tag with many attributes. + + SYNOPSIS + print_xml_row() + xml_file - output file + row_name - xml tag name + tableRes - query result + row - result row + + DESCRIPTION + Print tag with many attribute to the xml_file. Format is: + \t\t<row_name Atr1="Val1" Atr2="Val2"... /> + NOTE + All atributes and values will be quoted before output. +*/ + +static void print_xml_row(FILE *xml_file, const char *row_name, + MYSQL_RES *tableRes, MYSQL_ROW *row) +{ + uint i; + MYSQL_FIELD *field; + ulong *lengths= mysql_fetch_lengths(tableRes); + + fprintf(xml_file, "\t\t<%s", row_name); + mysql_field_seek(tableRes, 0); + for (i= 0; (field= mysql_fetch_field(tableRes)); i++) + { + if ((*row)[i]) + { + fputs(" ", xml_file); + print_quoted_xml(xml_file, field->name, field->name_length); + fputs("=\"", xml_file); + print_quoted_xml(xml_file, (*row)[i], lengths[i]); + fputs("\"", xml_file); + } + } + fputs(" />\n", xml_file); +} + +/* getStructure -- retrievs database structure, prints out corresponding CREATE statement and fills out insert_pat. @@ -613,7 +821,7 @@ static uint getTableStructure(char *table, char* db) (opt_quoted || opt_keywords)); result_table= quote_name(table, table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); - if (!mysql_query(sock,insert_pat)) + if (!opt_xml && !mysql_query(sock,insert_pat)) { /* using SHOW CREATE statement */ if (!tFlag) @@ -621,6 +829,31 @@ static uint getTableStructure(char *table, char* db) /* Make an sql-file, if path was given iow. option -T was given */ char buff[20+FN_REFLEN]; + if (opt_compatible_mode) + { + char *end; + uint i; + + sprintf(buff, "/*!41000 SET @@sql_mode=\""); + end= strend(buff); + for (i= 0; opt_compatible_mode; opt_compatible_mode>>= 1, i++) + { + if (opt_compatible_mode & 1) + { + end= strmov(end, compatible_mode_names[i]); + end= strmov(end, ","); + } + } + end= strmov(end-1, "\" */"); + if (mysql_query(sock, buff)) + { + fprintf(stderr, "%s: Can't set the compatible mode '%s' (%s)\n", + my_progname, table, mysql_error(sock)); + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } + } + sprintf(buff,"show create table %s", result_table); if (mysql_query(sock, buff)) { @@ -644,15 +877,14 @@ static uint getTableStructure(char *table, char* db) write_header(sql_file, db); } if (!opt_xml && opt_comments) - fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n", + fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n", result_table); if (opt_drop) fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table); tableRes=mysql_store_result(sock); row=mysql_fetch_row(tableRes); - if (!opt_xml) - fprintf(sql_file, "%s;\n", row[1]); + fprintf(sql_file, "%s;\n", row[1]); mysql_free_result(tableRes); } sprintf(insert_pat,"show fields from %s", result_table); @@ -726,7 +958,10 @@ static uint getTableStructure(char *table, char* db) result_table); if (opt_drop) fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",result_table); - fprintf(sql_file, "CREATE TABLE %s (\n", result_table); + if (!opt_xml) + fprintf(sql_file, "CREATE TABLE %s (\n", result_table); + else + print_xml_tag1(sql_file, "\t", "table_structure name=", table, "\n"); } if (cFlag) sprintf(insert_pat, "INSERT %sINTO %s (", delayed, result_table); @@ -743,7 +978,7 @@ static uint getTableStructure(char *table, char* db) ulong *lengths=mysql_fetch_lengths(tableRes); if (init) { - if (!tFlag) + if (!opt_xml && !tFlag) fputs(",\n",sql_file); if (cFlag) strpos=strmov(strpos,", "); @@ -753,6 +988,12 @@ static uint getTableStructure(char *table, char* db) strpos=strmov(strpos,quote_name(row[SHOW_FIELDNAME], name_buff, 0)); if (!tFlag) { + if (opt_xml) + { + print_xml_row(sql_file, "field", tableRes, &row); + continue; + } + if (opt_keywords) fprintf(sql_file, " %s.%s %s", result_table, quote_name(row[SHOW_FIELDNAME],name_buff, 0), @@ -814,6 +1055,12 @@ static uint getTableStructure(char *table, char* db) keynr=0; while ((row=mysql_fetch_row(tableRes))) { + if (opt_xml) + { + print_xml_row(sql_file, "key", tableRes, &row); + continue; + } + if (atoi(row[3]) == 1) { if (keynr++) @@ -824,7 +1071,8 @@ static uint getTableStructure(char *table, char* db) 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,0)); + fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff, + 0)); } else putc(',', sql_file); @@ -832,9 +1080,12 @@ static uint getTableStructure(char *table, char* db) if (row[7]) fprintf(sql_file, " (%s)",row[7]); /* Sub key */ } - if (keynr) - putc(')', sql_file); - fputs("\n)",sql_file); + if (!opt_xml) + { + if (keynr) + putc(')', sql_file); + fputs("\n)",sql_file); + } /* Get MySQL specific create options */ if (create_options) @@ -861,15 +1112,25 @@ static uint getTableStructure(char *table, char* db) } 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); + if (opt_xml) + { + print_xml_row(sql_file, "options", tableRes, &row); + } + 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 (!opt_xml) + fputs(";\n", sql_file); + else + fputs("\t</table_structure>\n", sql_file); } } if (cFlag) @@ -1049,7 +1310,7 @@ static void dumpTable(uint numFields, char *table) rownr=0; init_length=(uint) strlen(insert_pat)+4; if (opt_xml) - fprintf(md_result_file, "\t<table name=\"%s\">\n", table); + print_xml_tag1(md_result_file, "\t", "table_data name=", table, "\n"); if (opt_autocommit) fprintf(md_result_file, "set autocommit=0;\n"); @@ -1064,7 +1325,7 @@ static void dumpTable(uint numFields, char *table) mysql_field_seek(res,0); if (opt_xml) - fprintf(md_result_file, "\t<row>\n"); + fputs("\t<row>\n", md_result_file); for (i = 0; i < mysql_num_fields(res); i++) { @@ -1106,7 +1367,8 @@ static void dumpTable(uint numFields, char *table) { /* change any strings ("inf", "-inf", "nan") into NULL */ char *ptr = row[i]; - if (isalpha(*ptr) || (*ptr == '-' && isalpha(ptr[1]))) + if (my_isalpha(charset_info, *ptr) || (*ptr == '-' && + my_isalpha(charset_info, ptr[1]))) dynstr_append(&extended_row, "NULL"); else { @@ -1140,8 +1402,12 @@ static void dumpTable(uint numFields, char *table) if (!IS_NUM_FIELD(field)) { if (opt_xml) - print_quoted_xml(md_result_file, field->name, row[i], - lengths[i]); + { + print_xml_tag1(md_result_file, "\t\t", "field name=", + field->name, ""); + print_quoted_xml(md_result_file, row[i], lengths[i]); + fputs("</field>\n", md_result_file); + } else unescape(md_result_file, row[i], lengths[i]); } @@ -1150,29 +1416,33 @@ static void dumpTable(uint numFields, char *table) /* change any strings ("inf", "-inf", "nan") into NULL */ char *ptr = row[i]; if (opt_xml) - fprintf(md_result_file, "\t\t<field name=\"%s\">%s</field>\n", - field->name,!isalpha(*ptr) ?ptr: "NULL"); - else if (isalpha(*ptr) || (*ptr == '-' && isalpha(ptr[1]))) - fputs("NULL", md_result_file); - else { - if (field->type == FIELD_TYPE_DECIMAL) - { - /* add " signs around */ - fputs("\"", md_result_file); - fputs(ptr, md_result_file); - fputs("\"", md_result_file); - } - else - fputs(ptr, md_result_file); + print_xml_tag1(md_result_file, "\t\t", "field name=", + field->name, ""); + fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL", + md_result_file); + fputs("</field>\n", md_result_file); } + else if (my_isalpha(charset_info, *ptr) || + (*ptr == '-' && my_isalpha(charset_info, ptr[1]))) + fputs("NULL", md_result_file); + else if (field->type == FIELD_TYPE_DECIMAL) + { + /* add " signs around */ + fputs("\"", md_result_file); + fputs(ptr, md_result_file); + fputs("\"", md_result_file); + } + else + fputs(ptr, md_result_file); + } } } else { if (opt_xml) - fprintf(md_result_file, "\t\t<field name=\"%s\">%s</field>\n", - field->name, "NULL"); + print_xml_tag1(md_result_file, "\t\t", "field name=", + field->name, "NULL</field>\n"); else fputs("NULL", md_result_file); } @@ -1180,7 +1450,7 @@ static void dumpTable(uint numFields, char *table) } if (opt_xml) - fprintf(md_result_file, "\t</row>\n"); + fputs("\t</row>\n", md_result_file); if (extended_insert) { @@ -1195,15 +1465,12 @@ static void dumpTable(uint numFields, char *table) } else { - if (row_break && !opt_xml) + if (row_break) fputs(";\n", md_result_file); row_break=1; /* This is first row */ - if (!opt_xml) - { - fputs(insert_pat,md_result_file); - fputs(extended_row.str,md_result_file); - } + fputs(insert_pat,md_result_file); + fputs(extended_row.str,md_result_file); total_length = row_length+init_length; } } @@ -1213,7 +1480,7 @@ static void dumpTable(uint numFields, char *table) /* XML - close table tag and supress regular output */ if (opt_xml) - fprintf(md_result_file, "\t</table>\n"); + fputs("\t</table_data>\n", md_result_file); else if (extended_insert && row_break) fputs(";\n", md_result_file); /* If not empty table */ fflush(md_result_file); @@ -1241,27 +1508,6 @@ static void dumpTable(uint numFields, char *table) } /* dumpTable */ -static void print_quoted_xml(FILE *output, char *fname, char *str, uint len) -{ - const char *end; - - fprintf(output, "\t\t<field name=\"%s\">", fname); - for (end = str + len; str != end; str++) - { - if (*str == '<') - fputs("<", output); - else if (*str == '>') - fputs(">", output); - else if (*str == '&') - fputs("&", output); - else if (*str == '\"') - fputs(""", output); - else - fputc(*str, output); - } - fprintf(output, "</field>\n"); -} - static char *getTableName(int reset) { static MYSQL_RES *res = NULL; @@ -1332,24 +1578,48 @@ static int init_dumping(char *database) { if (opt_databases || opt_alldbs) { - /* length of table name * 2 (if name contain quotas), 2 quotas and 0 */ + /* + length of table name * 2 (if name contain quotas), 2 quotas and 0 + */ char quoted_database_buf[64*2+3]; char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted); if (opt_comments) - fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", database); + fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase); if (!opt_create_db) - fprintf(md_result_file,"\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", + { + char qbuf[256]; + MYSQL_ROW row; + MYSQL_RES *dbinfo; + + sprintf(qbuf,"SHOW CREATE DATABASE WITH IF NOT EXISTS %s", qdatabase); - fprintf(md_result_file,"\nUSE %s;\n", database); + + if (mysql_query(sock, qbuf) || !(dbinfo = mysql_store_result(sock))) + { + /* Old server version, dump generic CREATE DATABASE */ + fprintf(md_result_file, + "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", + qdatabase); + } + else + { + row = mysql_fetch_row(dbinfo); + if (row[1]) + { + fprintf(md_result_file,"\n%s;\n",row[1]); + } + } + } + fprintf(md_result_file,"\nUSE %s;\n", qdatabase); } } - if (extended_insert) - if (init_dynamic_string(&extended_row, "", 1024, 1024)) - exit(EX_EOM); + if (extended_insert && 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; @@ -1359,7 +1629,7 @@ static int dump_all_tables_in_db(char *database) if (init_dumping(database)) return 1; if (opt_xml) - fprintf(md_result_file, "<database name=\"%s\">\n", database); + print_xml_tag1(md_result_file, "", "database name=", database, "\n"); if (lock_tables) { DYNAMIC_STRING query; @@ -1387,7 +1657,7 @@ static int dump_all_tables_in_db(char *database) dumpTable(numrows,table); } if (opt_xml) - fprintf(md_result_file, "</database>\n"); + fputs("</database>\n", md_result_file); if (lock_tables) mysql_query(sock,"UNLOCK_TABLES"); return 0; @@ -1425,7 +1695,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) /* We shall countinue here, if --force was given */ } if (opt_xml) - fprintf(md_result_file, "<database name=\"%s\">\n", db); + print_xml_tag1(md_result_file, "", "database name=", db, "\n"); for (; tables > 0 ; tables-- , table_names++) { numrows = getTableStructure(*table_names, db); @@ -1433,13 +1703,55 @@ static int dump_selected_tables(char *db, char **table_names, int tables) dumpTable(numrows, *table_names); } if (opt_xml) - fprintf(md_result_file, "</database>\n"); + fputs("</database>\n", md_result_file); if (lock_tables) mysql_query(sock,"UNLOCK_TABLES"); return 0; } /* dump_selected_tables */ + +static ulong find_set(TYPELIB *lib, const char *x, uint length, + char **err_pos, uint *err_len) +{ + const char *end= x + length; + ulong found= 0; + uint find; + char buff[255]; + + *err_pos= 0; /* No error yet */ + while (end > x && my_isspace(charset_info, end[-1])) + end--; + + *err_len= 0; + if (x != end) + { + const char *start= x; + for (;;) + { + const char *pos= start; + uint var_len; + + for (; pos != end && *pos != ','; pos++) ; + var_len= (uint) (pos - start); + strmake(buff, start, min(sizeof(buff), var_len)); + find= find_type(buff, lib, var_len); + if (!find) + { + *err_pos= (char*) start; + *err_len= var_len; + } + else + found|= ((longlong) 1 << (find - 1)); + if (pos == end) + break; + start= pos + 1; + } + } + return found; +} + + /* 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, @@ -1607,6 +1919,9 @@ MASTER_LOG_POS=%s ;\n",row[0],row[1]); MYF(0), mysql_error(sock)); } else if (opt_single_transaction) /* Just to make it beautiful enough */ +#ifdef HAVE_SMEM + my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); +#endif { /* In case we were locking all tables, we did not start transaction @@ -1617,8 +1932,8 @@ MASTER_LOG_POS=%s ;\n",row[0],row[1]); if (mysql_query(sock, "COMMIT")) { my_printf_error(0, "Error: Couldn't execute 'COMMIT': %s", - MYF(0), mysql_error(sock)); - } + MYF(0), mysql_error(sock)); + } } dbDisconnect(current_host); write_footer(md_result_file); diff --git a/client/mysqlimport.c b/client/mysqlimport.c index c72e32dd2a7..5ad6d1dc429 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -43,16 +43,22 @@ static MYSQL mysql_connection; static char *opt_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_columns=0, *default_charset; -static uint opt_mysql_port=0; + *escaped=0, *opt_columns=0, + *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; +static uint opt_mysql_port= 0, opt_protocol= 0; static my_string opt_mysql_unix_port=0; static longlong opt_ignore_lines= -1; +static CHARSET_INFO *charset_info= &my_charset_latin1; #include <sslopt-vars.h> +#ifdef HAVE_SMEM +static char *shared_memory_base_name=0; +#endif + static struct my_option my_long_options[] = { {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory where character sets are", (gptr*) &charsets_dir, + "Directory where character sets are.", (gptr*) &charsets_dir, (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"default-character-set", OPT_DEFAULT_CHARSET, "Set the default character set.", (gptr*) &default_charset, @@ -64,8 +70,8 @@ static struct my_option my_long_options[] = {"compress", 'C', "Use compression in server/client protocol.", (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"debug",'#', "Output debug log. Often this is 'd:t:o,filename'", 0, 0, 0, - GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug",'#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0, + GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"delete", 'd', "First delete all rows from table.", (gptr*) &opt_delete, (gptr*) &opt_delete, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"fields-terminated-by", OPT_FTB, @@ -95,12 +101,12 @@ static struct my_option my_long_options[] = {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...", (gptr*) &lines_terminated, (gptr*) &lines_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"local", 'L', "Read all files through the client", (gptr*) &opt_local_file, + {"local", 'L', "Read all files through the client.", (gptr*) &opt_local_file, (gptr*) &opt_local_file, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"lock-tables", 'l', "Lock all tables for write.", (gptr*) &lock_tables, (gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"low-priority", OPT_LOW_PRIORITY, - "Use LOW_PRIORITY when updating the table", (gptr*) &opt_low_priority, + "Use LOW_PRIORITY when updating the table.", (gptr*) &opt_low_priority, (gptr*) &opt_low_priority, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to use when connecting to server. If password is not given it's asked from the tty.", @@ -112,8 +118,15 @@ static struct my_option my_long_options[] = {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, + {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"replace", 'r', "If duplicate unique key was found, replace old row.", (gptr*) &replace, (gptr*) &replace, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_SMEM + {"shared_memory_base_name", OPT_SHARED_MEMORY_BASE_NAME, + "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"silent", 's', "Be more silent.", (gptr*) &silent, (gptr*) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", @@ -181,10 +194,19 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; #ifdef __WIN__ case 'W': - opt_mysql_unix_port=MYSQL_NAMEDPIPE; + opt_protocol = MYSQL_PROTOCOL_PIPE; opt_local_file=1; break; #endif + case OPT_MYSQL_PROTOCOL: + { + if ((opt_protocol = find_type(argument, &sql_protocol_typelib,0)) == ~(ulong) 0) + { + fprintf(stderr, "Unknown option to protocol: %s\n", argument); + exit(1); + } + break; + } case '#': DBUG_PUSH(argument ? argument : "d:t:o"); break; @@ -216,11 +238,9 @@ static int get_options(int *argc, char ***argv) fprintf(stderr, "You can't use --ignore (-i) and --replace (-r) at the same time.\n"); return(1); } - if (default_charset) - { - if (set_default_charset_by_name(default_charset, MYF(MY_WME))) - exit(1); - } + if (!(charset_info= get_charset_by_csname(default_charset, + MY_CS_PRIMARY, MYF(MY_WME)))) + exit(1); if (*argc < 2) { usage(); @@ -353,6 +373,12 @@ static MYSQL *db_connect(char *host, char *database, char *user, char *passwd) mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); #endif + if (opt_protocol) + mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); +#ifdef HAVE_SMEM + if (shared_memory_base_name) + mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); +#endif if (!(sock= mysql_real_connect(&mysql_connection,host,user,passwd, database,opt_mysql_port,opt_mysql_unix_port, 0))) @@ -487,6 +513,9 @@ int main(int argc, char **argv) exitcode = error; db_disconnect(current_host, sock); my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); +#ifdef HAVE_SMEM + my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); +#endif free_defaults(argv_to_free); my_end(0); return(exitcode); diff --git a/client/mysqlmanager-pwgen.c b/client/mysqlmanager-pwgen.c index 57d91b52f49..1d942e207ad 100644 --- a/client/mysqlmanager-pwgen.c +++ b/client/mysqlmanager-pwgen.c @@ -29,14 +29,14 @@ const char* outfile=0,*user="root"; static struct my_option my_long_options[] = { - {"output-file", 'o', "Write the output to the file with the given name", + {"output-file", 'o', "Write the output to the file with the given name.", (gptr*) &outfile, (gptr*) &outfile, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"user", 'u', "Put given user in the password file", (gptr*) &user, + {"user", 'u', "Put given user in the password file.", (gptr*) &user, (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"help", '?', "Display this message and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, + {"help", '?', "Display this message and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"version", 'V', "Display version info", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, + {"version", 'V', "Display version info.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; diff --git a/client/mysqlshow.c b/client/mysqlshow.c index ccae43e4e27..9dc5c0a30f4 100644 --- a/client/mysqlshow.c +++ b/client/mysqlshow.c @@ -30,6 +30,12 @@ static my_string host=0,opt_password=0,user=0; static my_bool opt_show_keys=0,opt_compress=0,opt_status=0, tty_password=0; static uint opt_verbose=0; +static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; + +#ifdef HAVE_SMEM +static char *shared_memory_base_name=0; +#endif +static uint opt_protocol=0; static void get_options(int *argc,char ***argv); static uint opt_mysql_port=0; @@ -104,6 +110,14 @@ int main(int argc, char **argv) mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); #endif + if (opt_protocol) + mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); +#ifdef HAVE_SMEM + if (shared_memory_base_name) + mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); +#endif + mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); + if (!(mysql_real_connect(&mysql,host,user,opt_password, (first_argument_uses_wildcards) ? "" : argv[0],opt_mysql_port,opt_mysql_unix_port, 0))) @@ -131,6 +145,9 @@ int main(int argc, char **argv) mysql_close(&mysql); /* Close & free connection */ if (opt_password) my_free(opt_password,MYF(0)); +#ifdef HAVE_SMEM + my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); +#endif my_end(0); exit(error ? 1 : 0); return 0; /* No compiler warnings */ @@ -138,13 +155,16 @@ int main(int argc, char **argv) static struct my_option my_long_options[] = { - {"character-sets-dir", 'c', "Directory where character sets are", + {"character-sets-dir", 'c', "Directory where character sets are.", (gptr*) &charsets_dir, (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"compress", 'C', "Use compression in server/client protocol", + {"default-character-set", OPT_DEFAULT_CHARSET, + "Set the default character set.", (gptr*) &default_charset, + (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"compress", 'C', "Use compression in server/client protocol.", (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'", + {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -153,10 +173,10 @@ static struct my_option my_long_options[] = {"status", 'i', "Shows a lot of extra information about each table.", (gptr*) &opt_status, (gptr*) &opt_status, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"keys", 'k', "Show keys for table", (gptr*) &opt_show_keys, + {"keys", 'k', "Show keys for table.", (gptr*) &opt_show_keys, (gptr*) &opt_show_keys, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', - "Password to use when connecting to server. If password is not given it's asked from the tty.", + "Password to use when connecting to server. If password is not given it's asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, @@ -165,6 +185,13 @@ static struct my_option my_long_options[] = {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_SMEM + {"shared_memory_base_name", OPT_SHARED_MEMORY_BASE_NAME, + "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"socket", 'S', "Socket file to use for connection.", (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -180,7 +207,7 @@ static struct my_option my_long_options[] = NO_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; - + static void print_version(void) { @@ -230,9 +257,18 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'W': #ifdef __WIN__ - opt_mysql_unix_port=MYSQL_NAMEDPIPE; + opt_protocol = MYSQL_PROTOCOL_PIPE; #endif break; + case OPT_MYSQL_PROTOCOL: + { + if ((opt_protocol = find_type(argument, &sql_protocol_typelib,0)) == ~(ulong) 0) + { + fprintf(stderr, "Unknown option to protocol: %s\n", argument); + exit(1); + } + break; + } case '#': DBUG_PUSH(argument ? argument : "d:t:o"); break; @@ -528,7 +564,7 @@ list_fields(MYSQL *mysql,const char *db,const char *table, mysql_error(mysql)); return 1; } - end=strmov(strmov(query,"show /*!32332 FULL */ columns from "),table); + end=strmov(strmov(strmov(query,"show /*!32332 FULL */ columns from `"),table),"`"); if (wild && wild[0]) strxmov(end," like '",wild,"'",NullS); if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql))) @@ -550,7 +586,7 @@ list_fields(MYSQL *mysql,const char *db,const char *table, print_res_top(result); if (opt_show_keys) { - end=strmov(strmov(query,"show keys from "),table); + end=strmov(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", diff --git a/client/mysqltest.c b/client/mysqltest.c index e3aa78c05df..08b58f1ccfe 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -42,7 +42,7 @@ **********************************************************************/ -#define MTEST_VERSION "1.30" +#define MTEST_VERSION "2.1" #include <my_global.h> #include <mysql_embed.h> @@ -76,11 +76,6 @@ #endif #define MAX_SERVER_ARGS 20 -/* Defines to make this look like MySQL 4.1 */ -#define charset_info default_charset_info -#define my_isvar(A,B) isvar(B) -#define my_hash_insert(A,B) hash_insert((A), (B)) - /* Sometimes in a test the client starts before the server - to solve the problem, we try again @@ -91,7 +86,8 @@ #define MAX_CON_TRIES 5 #define SLAVE_POLL_INTERVAL 300000 /* 0.3 of a sec */ - +#define DEFAULT_DELIMITER ";" +#define MAX_DELIMITER 16 enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD, OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT, OPT_SKIP_SAFEMALLOC, @@ -119,12 +115,15 @@ static FILE** cur_file; static FILE** file_stack_end; static uint lineno_stack[MAX_INCLUDE_DEPTH]; static char TMPDIR[FN_REFLEN]; +static char delimiter[MAX_DELIMITER]= DEFAULT_DELIMITER; +static uint delimiter_length= 1; static int *cur_block, *block_stack_end; static int block_stack[BLOCK_STACK_DEPTH]; static int block_ok_stack[BLOCK_STACK_DEPTH]; static uint global_expected_errno[MAX_EXPECTED_ERRORS], global_expected_errors; +static CHARSET_INFO *charset_info= &my_charset_latin1; static int embedded_server_arg_count=0; static char *embedded_server_args[MAX_SERVER_ARGS]; @@ -213,7 +212,8 @@ Q_WAIT_FOR_SLAVE_TO_STOP, Q_REQUIRE_VERSION, Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS, Q_ENABLE_INFO, Q_DISABLE_INFO, -Q_EXEC, +Q_EXEC, Q_DELIMITER, + Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ Q_COMMENT_WITH_COMMAND @@ -285,6 +285,7 @@ const char *command_names[]= "enable_info", "disable_info", "exec", + "delimiter", 0 }; @@ -346,11 +347,11 @@ static void get_replace_column(struct st_query *q); static void free_replace_column(); /* Disable functions that only exist in MySQL 4.0 */ -#if MYSQL_VERSION_ID < 40000 || defined(EMBEDDED_LIBRARY) +#if MYSQL_VERSION_ID < 40000 void mysql_enable_rpl_parse(MYSQL* mysql __attribute__((unused))) {} void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {} int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { return 1; } -int mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } +my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } #endif static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, int len); @@ -1476,7 +1477,8 @@ int safe_connect(MYSQL* con, const char* host, const char* user, int i; for (i = 0; i < MAX_CON_TRIES; ++i) { - if (mysql_real_connect(con, host,user, pass, db, port, sock, 0)) + if (mysql_real_connect(con, host,user, pass, db, port, sock, + CLIENT_MULTI_STATEMENTS)) { con_error = 0; break; @@ -1626,24 +1628,46 @@ int do_while(struct st_query* q) } +my_bool end_of_query(int c, char* p) +{ + uint i, j; + int tmp[MAX_DELIMITER]= {0}; + + for (i= 0; c == *(delimiter + i) && i < delimiter_length; + i++, c= fgetc(*cur_file)) + tmp[i]= c; + tmp[i]= c; + + for (j= i; j > 0 && i != delimiter_length; j--) + ungetc(tmp[j], *cur_file); + if (i == delimiter_length) + { + ungetc(tmp[i], *cur_file); + *p= 0; + return 1; + } + return 0; +} + + int read_line(char* buf, int size) { int c; - char* p = buf, *buf_end = buf + size-1; - int no_save = 0; + char* p= buf, *buf_end= buf + size - 1; + int no_save= 0; enum {R_NORMAL, R_Q1, R_ESC_Q_Q1, R_ESC_Q_Q2, R_ESC_SLASH_Q1, R_ESC_SLASH_Q2, - R_Q2, R_COMMENT, R_LINE_START} state = R_LINE_START; + R_Q2, R_COMMENT, R_LINE_START} state= R_LINE_START; start_lineno= *lineno; for (; p < buf_end ;) { - no_save = 0; - c = fgetc(*cur_file); + no_save= 0; + c= fgetc(*cur_file); if (feof(*cur_file)) { if ((*cur_file) != stdin) - my_fclose(*cur_file,MYF(0)); + my_fclose(*cur_file, MYF(0)); cur_file--; lineno--; if (cur_file == file_stack) @@ -1654,11 +1678,8 @@ int read_line(char* buf, int size) switch(state) { case R_NORMAL: /* Only accept '{' in the beginning of a line */ - if (c == ';') - { - *p = 0; + if (end_of_query(c, p)) return 0; - } else if (c == '\'') state = R_Q1; else if (c == '"') @@ -1672,7 +1693,7 @@ int read_line(char* buf, int size) case R_COMMENT: if (c == '\n') { - *p=0; + *p= 0; (*lineno)++; return 0; } @@ -1682,78 +1703,72 @@ int read_line(char* buf, int size) { state = R_COMMENT; } - else if (my_isspace(charset_info,c)) + else if (my_isspace(charset_info, c)) { if (c == '\n') start_lineno= ++*lineno; /* Query hasn't started yet */ - no_save = 1; + no_save= 1; } else if (c == '}') { - *buf++ = '}'; - *buf = 0; + *buf++= '}'; + *buf= 0; return 0; } - else if (c == ';' || c == '{') + else if (end_of_query(c, p) || c == '{') { - *p = 0; + *p= 0; return 0; } else if (c == '\'') - state = R_Q1; + state= R_Q1; else if (c == '"') - state = R_Q2; + state= R_Q2; else - state = R_NORMAL; + state= R_NORMAL; break; case R_Q1: if (c == '\'') - state = R_ESC_Q_Q1; + state= R_ESC_Q_Q1; else if (c == '\\') - state = R_ESC_SLASH_Q1; + state= R_ESC_SLASH_Q1; break; case R_ESC_Q_Q1: - if (c == ';') - { - *p = 0; + if (end_of_query(c, p)) return 0; - } if (c != '\'') - state = R_NORMAL; + state= R_NORMAL; else - state = R_Q1; + state= R_Q1; break; case R_ESC_SLASH_Q1: - state = R_Q1; + state= R_Q1; break; case R_Q2: if (c == '"') - state = R_ESC_Q_Q2; + state= R_ESC_Q_Q2; else if (c == '\\') - state = R_ESC_SLASH_Q2; + state= R_ESC_SLASH_Q2; break; case R_ESC_Q_Q2: - if (c == ';') - { - *p = 0; + if (end_of_query(c, p)) return 0; - } if (c != '"') - state = R_NORMAL; + state= R_NORMAL; else - state = R_Q2; + state= R_Q2; break; case R_ESC_SLASH_Q2: - state = R_Q2; + state= R_Q2; break; } if (!no_save) - *p++ = c; + *p++= c; } - *p=0; /* Always end with \0 */ + *p= 0; /* Always end with \0 */ return feof(*cur_file); } @@ -1770,22 +1785,22 @@ int read_query(struct st_query** q_ptr) get_dynamic(&q_lines, (gptr) q_ptr, parser.current_line) ; return 0; } - if (!(*q_ptr=q=(struct st_query*) my_malloc(sizeof(*q), MYF(MY_WME))) || + if (!(*q_ptr= q= (struct st_query*) my_malloc(sizeof(*q), MYF(MY_WME))) || insert_dynamic(&q_lines, (gptr) &q)) die(NullS); - q->record_file[0] = 0; - q->require_file=0; - q->first_word_len = 0; + q->record_file[0]= 0; + q->require_file= 0; + q->first_word_len= 0; memcpy((gptr) q->expected_errno, (gptr) global_expected_errno, sizeof(global_expected_errno)); - q->expected_errors=global_expected_errors; - q->abort_on_error = global_expected_errno[0] == 0; - bzero((gptr) global_expected_errno,sizeof(global_expected_errno)); + q->expected_errors= global_expected_errors; + q->abort_on_error= global_expected_errno[0] == 0; + bzero((gptr) global_expected_errno, sizeof(global_expected_errno)); global_expected_errors=0; q->type = Q_UNKNOWN; - q->query_buf=q->query=0; + q->query_buf= q->query= 0; if (read_line(read_query_buf, sizeof(read_query_buf))) return 1; @@ -1795,20 +1810,20 @@ int read_query(struct st_query** q_ptr) } else if (p[0] == '-' && p[1] == '-') { - q->type = Q_COMMENT_WITH_COMMAND; - p+=2; /* To calculate first word */ + q->type= Q_COMMENT_WITH_COMMAND; + p+= 2; /* To calculate first word */ } else { if (*p == '!') { - q->abort_on_error = 0; + q->abort_on_error= 0; p++; if (*p == '$') { - expected_errno = 0; + expected_errno= 0; p++; - for (;my_isdigit(charset_info,*p);p++) + for (; my_isdigit(charset_info, *p); p++) expected_errno = expected_errno * 10 + *p - '0'; q->expected_errno[0] = expected_errno; q->expected_errno[1] = 0; @@ -1816,30 +1831,30 @@ int read_query(struct st_query** q_ptr) } } - while (*p && my_isspace(charset_info,*p)) + while (*p && my_isspace(charset_info, *p)) p++ ; if (*p == '@') { p++; p1 = q->record_file; - while (!my_isspace(charset_info,*p) && + while (!my_isspace(charset_info, *p) && p1 < q->record_file + sizeof(q->record_file) - 1) *p1++ = *p++; *p1 = 0; } } - while (*p && my_isspace(charset_info,*p)) + while (*p && my_isspace(charset_info, *p)) p++; - if (!(q->query_buf=q->query=my_strdup(p,MYF(MY_WME)))) + if (!(q->query_buf= q->query= my_strdup(p, MYF(MY_WME)))) die(NullS); /* Calculate first word and first argument */ - for (p=q->query; *p && !my_isspace(charset_info,*p) ; p++) ; - q->first_word_len = (uint) (p - q->query); - while (*p && my_isspace(charset_info,*p)) + for (p= q->query; *p && !my_isspace(charset_info, *p) ; p++) ; + q->first_word_len= (uint) (p - q->query); + while (*p && my_isspace(charset_info, *p)) p++; - q->first_argument=p; - q->end = strend(q->query); + q->first_argument= p; + q->end= strend(q->query); parser.read_lines++; return 0; } @@ -2133,12 +2148,12 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) int run_query(MYSQL* mysql, struct st_query* q, int flags) { - MYSQL_RES* res = 0; - int i, error = 0; + MYSQL_RES* res= 0; + int i, error= 0, err= 0, counter= 0; DYNAMIC_STRING *ds; DYNAMIC_STRING ds_tmp; DYNAMIC_STRING eval_query; - char* query; + char* query, buff[MAX_DELIMITER + 1]= {0}; int query_len; DBUG_ENTER("run_query"); @@ -2166,123 +2181,159 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) if ((flags & QUERY_SEND) && mysql_send_query(mysql, query, query_len)) die("At line %u: unable to send query '%s'(mysql_errno=%d,errno=%d)", - start_lineno, query, - mysql_errno(mysql), errno); - if ((flags & QUERY_SEND) && !disable_query_log) - { - replace_dynstr_append_mem(ds,query, query_len); - dynstr_append_mem(ds,";\n",2); - } - if (!(flags & QUERY_REAP)) - DBUG_RETURN(0); + start_lineno, query, mysql_errno(mysql), errno); - if (mysql_read_query_result(mysql) || - (!(last_result = res = mysql_store_result(mysql)) && - mysql_field_count(mysql))) + do { - if (q->require_file) + if ((flags & QUERY_SEND) && !disable_query_log && !counter) { - abort_not_supported_test(); + replace_dynstr_append_mem(ds,query, query_len); + sprintf(buff, "%s\n", delimiter); + dynstr_append_mem(ds, buff, delimiter_length + 1); } - if (q->abort_on_error) - die("At line %u: query '%s' failed: %d: %s", start_lineno, query, - mysql_errno(mysql), mysql_error(mysql)); - else + if (!(flags & QUERY_REAP)) + DBUG_RETURN(0); + + if ((!counter && (*mysql->methods->read_query_result)(mysql)) || + (!(last_result= res= mysql_store_result(mysql)) && + mysql_field_count(mysql))) { - for (i=0 ; (uint) i < q->expected_errors ; i++) + if (q->require_file) + { + abort_not_supported_test(); + } + if (q->abort_on_error) + die("At line %u: query '%s' failed: %d: %s", start_lineno, query, + mysql_errno(mysql), mysql_error(mysql)); + else { - if ((q->expected_errno[i] == mysql_errno(mysql))) + for (i=0 ; (uint) i < q->expected_errors ; i++) { - if (i == 0 && q->expected_errors == 1) + if ((q->expected_errno[i] == mysql_errno(mysql))) { - /* Only log error if there is one possible error */ - replace_dynstr_append_mem(ds,mysql_error(mysql), - strlen(mysql_error(mysql))); - dynstr_append_mem(ds,"\n",1); + if (i == 0 && q->expected_errors == 1) + { + /* Only log error if there is one possible error */ + dynstr_append_mem(ds,"ERROR ",6); + replace_dynstr_append_mem(ds, mysql_sqlstate(mysql), + strlen(mysql_sqlstate(mysql))); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append_mem(ds,mysql_error(mysql), + strlen(mysql_error(mysql))); + dynstr_append_mem(ds,"\n",1); + } + /* Don't log error if we may not get an error */ + else if (q->expected_errno[0] != 0) + dynstr_append(ds,"Got one of the listed errors\n"); + goto end; /* Ok */ } - /* Don't log error if we may not get an error */ - else if (q->expected_errno[0] != 0) - dynstr_append(ds,"Got one of the listed errors\n"); - goto end; /* Ok */ } - } - DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); - replace_dynstr_append_mem(ds, mysql_error(mysql), - strlen(mysql_error(mysql))); - dynstr_append_mem(ds,"\n",1); - if (i) - { - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, mysql_errno(mysql), q->expected_errno[0]); - error= 1; + DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); + dynstr_append_mem(ds, "ERROR ",6); + replace_dynstr_append_mem(ds, mysql_sqlstate(mysql), + strlen(mysql_sqlstate(mysql))); + dynstr_append_mem(ds,": ",2); + replace_dynstr_append_mem(ds, mysql_error(mysql), + strlen(mysql_error(mysql))); + dynstr_append_mem(ds,"\n",1); + if (i) + { + verbose_msg("query '%s' failed with wrong errno %d instead of %d...", + q->query, mysql_errno(mysql), q->expected_errno[0]); + error= 1; + goto end; + } + verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql), + mysql_error(mysql)); + /* + if we do not abort on error, failure to run the query does + not fail the whole test case + */ goto end; } - verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql), - mysql_error(mysql)); - /* - if we do not abort on error, failure to run the query does - not fail the whole test case - */ - goto end; + /*{ + verbose_msg("failed in mysql_store_result for query '%s' (%d)", query, + mysql_errno(mysql)); + error = 1; + goto end; + }*/ } - /*{ - verbose_msg("failed in mysql_store_result for query '%s' (%d)", query, - mysql_errno(mysql)); + + if (q->expected_errno[0]) + { error = 1; + verbose_msg("query '%s' succeeded - should have failed with errno %d...", + q->query, q->expected_errno[0]); goto end; - }*/ - } - - if (q->expected_errno[0]) - { - error = 1; - verbose_msg("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0]); - goto end; - } + } - if (!disable_result_log) - { - if (res) + if (!disable_result_log) { - int num_fields= mysql_num_fields(res); - MYSQL_FIELD *fields= mysql_fetch_fields(res); - for (i = 0; i < num_fields; i++) + if (res) { - if (i) - dynstr_append_mem(ds, "\t", 1); - dynstr_append(ds, fields[i].name); + int num_fields= mysql_num_fields(res); + MYSQL_FIELD *fields= mysql_fetch_fields(res); + + for (i = 0; i < num_fields; i++) + { + if (i) + dynstr_append_mem(ds, "\t", 1); + dynstr_append(ds, fields[i].name); + } + dynstr_append_mem(ds, "\n", 1); + append_result(ds, res); } - dynstr_append_mem(ds, "\n", 1); - append_result(ds, res); - } - if (!disable_info && mysql_info(mysql)) - { - dynstr_append(ds, "info: "); - dynstr_append(ds, mysql_info(mysql)); - dynstr_append_mem(ds, "\n", 1); + /* Add all warnings to the result */ + if (!disable_warnings && mysql_warning_count(mysql)) + { + MYSQL_RES *warn_res=0; + uint count= mysql_warning_count(mysql); + if (!mysql_real_query(mysql, "SHOW WARNINGS", 13)) + { + warn_res= mysql_store_result(mysql); + } + if (!warn_res) + verbose_msg("Warning count is %u but didn't get any warnings\n", + count); + else + { + dynstr_append_mem(ds, "Warnings:\n", 10); + append_result(ds, warn_res); + mysql_free_result(warn_res); + } + } + if (!disable_info && mysql_info(mysql)) + { + dynstr_append(ds, "info: "); + dynstr_append(ds, mysql_info(mysql)); + dynstr_append_mem(ds, "\n", 1); + } } - } - if (glob_replace) - free_replace(); + if (glob_replace) + free_replace(); - if (record) - { - if (!q->record_file[0] && !result_file) - die("At line %u: Missing result file", start_lineno); - if (!result_file) - str_to_file(q->record_file, ds->str, ds->length); - } - else if (q->record_file[0]) - { - error = check_result(ds, q->record_file, q->require_file); - } + if (record) + { + if (!q->record_file[0] && !result_file) + die("At line %u: Missing result file", start_lineno); + if (!result_file) + str_to_file(q->record_file, ds->str, ds->length); + } + else if (q->record_file[0]) + { + error = check_result(ds, q->record_file, q->require_file); + } + if (res) + mysql_free_result(res); + last_result= 0; + counter++; + } while (!(err= mysql_next_result(mysql))); + if (err >= 1) + mysql_error(mysql); end: - if (res) - mysql_free_result(res); last_result=0; if (ds == &ds_tmp) dynstr_free(&ds_tmp); @@ -2379,7 +2430,7 @@ static void init_var_hash(MYSQL *mysql) { VAR *v; DBUG_ENTER("init_var_hash"); - if (hash_init(&var_hash, + if (hash_init(&var_hash, charset_info, 1024, 0, 0, get_var_key, var_free, MYF(0))) die("Variable hash initialization failed"); var_from_env("MASTER_MYPORT", "9306"); @@ -2402,7 +2453,7 @@ int main(int argc, char **argv) my_bool require_file=0, q_send_flag=0; char save_file[FN_REFLEN]; MY_INIT(argv[0]); - { + DBUG_ENTER("main"); DBUG_PROCESS(argv[0]); @@ -2497,6 +2548,10 @@ int main(int argc, char **argv) case Q_DEC: do_dec(q); break; case Q_ECHO: do_echo(q); break; case Q_SYSTEM: do_system(q); break; + case Q_DELIMITER: + strmake(delimiter, q->first_argument, sizeof(delimiter) - 1); + delimiter_length= strlen(delimiter); + break; case Q_LET: do_let(q); break; case Q_EVAL_RESULT: eval_result = 1; break; case Q_EVAL: @@ -2623,9 +2678,9 @@ int main(int argc, char **argv) free_used_memory(); exit(error ? 1 : 0); return error ? 1 : 0; /* Keep compiler happy */ - } } + /* Read arguments for embedded server and put them into embedded_server_args_count and embedded_server_args[] diff --git a/client/select_test.c b/client/select_test.c deleted file mode 100644 index ee2a9192865..00000000000 --- a/client/select_test.c +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright (C) 2000 MySQL 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 */ - -#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 deleted file mode 100644 index df2b3037c00..00000000000 --- a/client/showdb_test.c +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (C) 2000 MySQL 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 */ - - -#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 index 3c5e481eaad..65a9ff68c53 100644 --- a/client/sql_string.cc +++ b/client/sql_string.cc @@ -40,19 +40,16 @@ extern void sql_element_free(void *ptr); bool String::real_alloc(uint32 arg_length) { arg_length=ALIGN_SIZE(arg_length+1); + str_length=0; 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; } @@ -94,36 +91,58 @@ bool String::realloc(uint32 alloc_length) return FALSE; } -bool String::set(longlong num) +bool String::set(longlong num, CHARSET_INFO *cs) { - if (alloc(21)) + uint l=20*cs->mbmaxlen+1; + + if (alloc(l)) return TRUE; - str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr); + if (cs->cset->snprintf == my_snprintf_8bit) + { + str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr); + } + else + { + str_length=cs->cset->snprintf(cs,Ptr,l,"%d",num); + } + str_charset=cs; return FALSE; } -bool String::set(ulonglong num) +bool String::set(ulonglong num, CHARSET_INFO *cs) { - if (alloc(21)) + uint l=20*cs->mbmaxlen+1; + + if (alloc(l)) return TRUE; - str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr); + if (cs->cset->snprintf == my_snprintf_8bit) + { + str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr); + } + else + { + str_length=cs->cset->snprintf(cs,Ptr,l,"%d",num); + } + str_charset=cs; return FALSE; } -bool String::set(double num,uint decimals) +bool String::set(double num,uint decimals, CHARSET_INFO *cs) { char buff[331]; + + str_charset=cs; if (decimals >= NOT_FIXED_DEC) { sprintf(buff,"%.14g",num); // Enough for a DATETIME - return copy(buff, (uint32) strlen(buff)); + return copy(buff, (uint32) strlen(buff), &my_charset_latin1, cs); } #ifdef HAVE_FCONVERT int decpt,sign; char *pos,*to; VOID(fconvert(num,(int) decimals,&decpt,&sign,buff+1)); - if (!isdigit(buff[1])) + if (!my_isdigit(&my_charset_latin1, buff[1])) { // Nan or Inf pos=buff+1; if (sign) @@ -131,7 +150,7 @@ bool String::set(double num,uint decimals) buff[0]='-'; pos=buff; } - return copy(pos,(uint32) strlen(pos)); + return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs); } if (alloc((uint32) ((uint32) decpt+3+decimals))) return TRUE; @@ -181,7 +200,7 @@ end: #else sprintf(buff,"%.*f",(int) decimals,num); #endif - return copy(buff,(uint32) strlen(buff)); + return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs); #endif } @@ -203,16 +222,67 @@ bool String::copy(const String &str) str_length=str.str_length; bmove(Ptr,str.Ptr,str_length); // May be overlapping Ptr[str_length]=0; + str_charset=str.str_charset; return FALSE; } -bool String::copy(const char *str,uint32 arg_length) +bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs) { if (alloc(arg_length)) return TRUE; if ((str_length=arg_length)) memcpy(Ptr,str,arg_length); Ptr[arg_length]=0; + str_charset=cs; + return FALSE; +} + +/* Copy with charset convertion */ +bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *from, CHARSET_INFO *to) +{ + uint32 new_length=to->mbmaxlen*arg_length; + int cnvres; + my_wc_t wc; + const uchar *s=(const uchar *)str; + const uchar *se=s+arg_length; + uchar *d, *de; + + if (alloc(new_length)) + return TRUE; + + d=(uchar *)Ptr; + de=d+new_length; + + for (str_length=new_length ; s < se && d < de ; ) + { + if ((cnvres=from->cset->mb_wc(from,&wc,s,se)) > 0 ) + { + s+=cnvres; + } + else if (cnvres==MY_CS_ILSEQ) + { + s++; + wc='?'; + } + else + break; + +outp: + if((cnvres=to->cset->wc_mb(to,wc,d,de)) >0 ) + { + d+=cnvres; + } + else if (cnvres==MY_CS_ILUNI && wc!='?') + { + wc='?'; + goto outp; + } + else + break; + } + Ptr[new_length]=0; + length((uint32) (d-(uchar *)Ptr)); + str_charset=to; return FALSE; } @@ -234,7 +304,7 @@ bool String::fill(uint32 max_length,char fill_char) void String::strip_sp() { - while (str_length && isspace(Ptr[str_length-1])) + while (str_length && my_isspace(str_charset,Ptr[str_length-1])) str_length--; } @@ -296,10 +366,10 @@ uint32 String::numchars() register uint32 n=0,mblen; register const char *mbstr=Ptr; register const char *end=mbstr+str_length; - if (use_mb(default_charset_info)) + if (use_mb(str_charset)) { while (mbstr < end) { - if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen; + if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen; else ++mbstr; ++n; } @@ -316,11 +386,11 @@ int String::charpos(int i,uint32 offset) register uint32 mblen; register const char *mbstr=Ptr+offset; register const char *end=Ptr+str_length; - if (use_mb(default_charset_info)) + if (use_mb(str_charset)) { if (i<=0) return i; while (i && mbstr < end) { - if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen; + if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen; else ++mbstr; --i; } @@ -361,6 +431,39 @@ skipp: return -1; } +/* + Search after a string without regarding to case + This needs to be replaced when we have character sets per string +*/ + +int String::strstr_case(const String &s,uint32 offset) +{ + if (s.length()+offset <= str_length) + { + if (!s.length()) + return ((int) 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_charset->sort_order[*str++] == str_charset->sort_order[*search]) + { + register char *i,*j; + i=(char*) str; j=(char*) search+1; + while (j != search_end) + if (str_charset->sort_order[*i++] != + str_charset->sort_order[*j++]) + goto skipp; + return (int) (str-Ptr) -1; + } + } + } + return -1; +} /* ** Search string from end. Offset is offset to the end of string @@ -428,6 +531,44 @@ bool String::replace(uint32 offset,uint32 arg_length,const String &to) return FALSE; } +// added by Holyfoot for "geometry" needs +int String::reserve(uint32 space_needed, uint32 grow_by) +{ + if (Alloced_length < str_length + space_needed) + { + if (realloc(Alloced_length + max(space_needed, grow_by) - 1)) + return TRUE; + } + return FALSE; +} + +void String::qs_append(const char *str) +{ + int len = strlen(str); + memcpy(Ptr + str_length, str, len + 1); + str_length += len; +} + +void String::qs_append(double d) +{ + char *buff = Ptr + str_length; + sprintf(buff,"%.14g", d); + str_length += strlen(buff); +} + +void String::qs_append(double *d) +{ + double ld; + float8get(ld, (char*) d); + qs_append(ld); +} + +void String::qs_append(const char &c) +{ + Ptr[str_length] = c; + str_length += sizeof(c); +} + int sortcmp(const String *x,const String *y) { @@ -435,28 +576,38 @@ int sortcmp(const String *x,const String *y) 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)) + if (use_strnxfrm(x->str_charset)) { #ifndef CMP_ENDSPACE - while (x_len && isspace(s[x_len-1])) + while (x_len && my_isspace(x->str_charset,s[x_len-1])) x_len--; - while (y_len && isspace(t[y_len-1])) + while (y_len && my_isspace(x->str_charset,t[y_len-1])) y_len--; #endif - return my_strnncoll(default_charset_info, + return my_strnncoll(x->str_charset, (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 (x->str_charset->sort_order) { - 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]]); + while (len--) + { + if (x->str_charset->sort_order[(uchar) *s++] != + x->str_charset->sort_order[(uchar) *t++]) + return ((int) x->str_charset->sort_order[(uchar) s[-1]] - + (int) x->str_charset->sort_order[(uchar) t[-1]]); + } + } + else + { + while (len--) + { + if (*s++ != *t++) + return ((int) s[-1] - (int) t[-1]); + } } #ifndef CMP_ENDSPACE /* Don't compare end space in strings */ @@ -465,14 +616,14 @@ int sortcmp(const String *x,const String *y) { const char *end=t+y_len; for (; t != end ; t++) - if (!isspace(*t)) + if (!my_isspace(x->str_charset,*t)) return -1; } else { const char *end=s+x_len; for (; s != end ; s++) - if (!isspace(*s)) + if (!my_isspace(x->str_charset,*s)) return 1; } return 0; @@ -480,9 +631,7 @@ int sortcmp(const String *x,const String *y) #else return (int) (x_len-y_len); #endif /* CMP_ENDSPACE */ -#ifdef USE_STRCOLL } -#endif } @@ -514,240 +663,9 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length) return from; // Actually an error if ((to->str_length=min(from->str_length,from_length))) memcpy(to->Ptr,from->Ptr,to->str_length); + to->str_charset=from->str_charset; 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; - LINT_INIT(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 index cffe78936a0..aec40466d2b 100644 --- a/client/sql_string.h +++ b/client/sql_string.h @@ -24,31 +24,56 @@ #define NOT_FIXED_DEC 31 #endif +class String; +int sortcmp(const String *a,const String *b); +int stringcmp(const String *a,const String *b); +String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); + class String { char *Ptr; uint32 str_length,Alloced_length; bool alloced; + CHARSET_INFO *str_charset; public: String() - { Ptr=0; str_length=Alloced_length=0; alloced=0; } + { + Ptr=0; str_length=Alloced_length=0; alloced=0; + str_charset= &my_charset_latin1; + } String(uint32 length_arg) - { alloced=0; Alloced_length=0; (void) real_alloc(length_arg); } - String(const char *str) - { Ptr=(char*) str; str_length=(uint) 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;} + { + alloced=0; Alloced_length=0; (void) real_alloc(length_arg); + str_charset= &my_charset_latin1; + } + String(const char *str, CHARSET_INFO *cs) + { + Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0; + str_charset=cs; + } + String(const char *str,uint32 len, CHARSET_INFO *cs) + { + Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0; + str_charset=cs; + } + String(char *str,uint32 len, CHARSET_INFO *cs) + { + Ptr=(char*) str; Alloced_length=str_length=len; alloced=0; + str_charset=cs; + } String(const String &str) - { Ptr=str.Ptr ; str_length=str.str_length ; - Alloced_length=str.Alloced_length; alloced=0; } - + { + Ptr=str.Ptr ; str_length=str.str_length ; + Alloced_length=str.Alloced_length; alloced=0; + str_charset=str.str_charset; + } static void *operator new(size_t size) { return (void*) sql_alloc((uint) size); } static void operator delete(void *ptr_arg,size_t size) /*lint -e715 */ { sql_element_free(ptr_arg); } ~String() { free(); } + inline void set_charset(CHARSET_INFO *charset) { str_charset=charset; } + inline CHARSET_INFO *charset() const { return str_charset; } inline uint32 length() const { return str_length;} inline uint32 alloced_length() const { return Alloced_length;} inline char& operator [] (uint32 i) const { return Ptr[i]; } @@ -67,6 +92,14 @@ public: Ptr[str_length]=0; return Ptr; } + inline char *c_ptr_safe() + { + if (Ptr && str_length < Alloced_length) + Ptr[str_length]=0; + else + (void) realloc(str_length); + return Ptr; + } void set(String &str,uint32 offset,uint32 arg_length) { @@ -76,28 +109,31 @@ public: Alloced_length=str.Alloced_length-offset; else Alloced_length=0; + str_charset=str.str_charset; } - inline void set(char *str,uint32 arg_length) + inline void set(char *str,uint32 arg_length, CHARSET_INFO *cs) { free(); Ptr=(char*) str; str_length=Alloced_length=arg_length ; alloced=0; + str_charset=cs; } - inline void set(const char *str,uint32 arg_length) + inline void set(const char *str,uint32 arg_length, CHARSET_INFO *cs) { free(); Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0; + str_charset=cs; } - inline void set_quick(char *str,uint32 arg_length) + inline void set_quick(char *str,uint32 arg_length, CHARSET_INFO *cs) { if (!alloced) { Ptr=(char*) str; str_length=Alloced_length=arg_length; } + str_charset=cs; } - bool set(longlong num); - /* bool set(long num); */ - bool set(ulonglong num); - bool set(double num,uint decimals=2); + bool set(longlong num, CHARSET_INFO *cs); + bool set(ulonglong num, CHARSET_INFO *cs); + bool set(double num,uint decimals, CHARSET_INFO *cs); inline void free() { if (alloced) @@ -124,7 +160,7 @@ public: char *new_ptr; if (!(new_ptr=(char*) my_realloc(Ptr,arg_length,MYF(0)))) { - (void) my_free(Ptr,MYF(0)); + Alloced_length = 0; real_alloc(arg_length); } else @@ -148,11 +184,13 @@ public: 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 copy(const char *s,uint32 arg_length, CHARSET_INFO *cs); // Allocate new string + bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom, CHARSET_INFO *csto); bool append(const String &s); bool append(const char *s,uint32 arg_length=0); bool append(IO_CACHE* file, uint32 arg_length); int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1 + int strstr_case(const String &s,uint32 offset=0); 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) @@ -171,13 +209,57 @@ public: } bool fill(uint32 max_length,char fill); void strip_sp(); - inline void caseup() { ::caseup(Ptr,str_length); } - inline void casedn() { ::casedn(Ptr,str_length); } + inline void caseup() { my_caseup(str_charset,Ptr,str_length); } + inline void casedn() { my_casedn(str_charset,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); + + int reserve(uint32 space_needed) + { + return realloc(str_length + space_needed); + } + int reserve(uint32 space_needed, uint32 grow_by); + + /* + The following append operations do NOT check alloced memory + q_*** methods writes values of parameters itself + qs_*** methods writes string representation of value + */ + void q_append(const char &c) + { + Ptr[str_length++] = c; + } + void q_append(const uint32 &n) + { + int4store(Ptr + str_length, n); + str_length += 4; + } + void q_append(double d) + { + float8store(Ptr + str_length, d); + str_length += 8; + } + void q_append(double *d) + { + float8store(Ptr + str_length, *d); + str_length += 8; + } + void q_append(const char *data, uint32 data_len) + { + memcpy(Ptr + str_length, data, data_len); + str_length += data_len; + } + + void WriteAtPosition(int position, uint32 value) + { + int4store(Ptr + position,value); + } + + void qs_append(const char *str); + void qs_append(double d); + void qs_append(double *d); + void qs_append(const char &c); }; diff --git a/client/ssl_test.c b/client/ssl_test.c deleted file mode 100644 index 279c1e95fdc..00000000000 --- a/client/ssl_test.c +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (C) 2000 MySQL 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 */ - - -#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/thimble.cc b/client/thimble.cc deleted file mode 100644 index 94b75d8fb35..00000000000 --- a/client/thimble.cc +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright (C) 2000 MySQL 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 */ - -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include "my_my_global.h" - -static void spawn_stern_thread(pthread_t *t); -static int act_goofy(void); -static void *be_stern(void *); - -static struct { - pthread_mutex_t lock; - pthread_cond_t cond; - int msg; -} comm = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0 }; - - -int -main(void) -{ - pthread_t t; - spawn_stern_thread(&t); - - while (act_goofy() != 0) - /* do nothing */; - - pthread_exit(NULL); - - /* notreached */ - return EXIT_SUCCESS; -} - -static void spawn_stern_thread(pthread_t *t) -{ - pthread_attr_t attr; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - if (pthread_create(t, &attr, be_stern, NULL) != 0) - exit(EXIT_FAILURE); - - pthread_attr_destroy(&attr); -} - -static int act_goofy(void) -{ - int ret; - char buf[30]; - - fputs("Are you ready to act goofy (Y/n)? ", stdout); fflush(stdout); - fgets(buf, sizeof(buf), stdin); - pthread_mutex_lock(&comm.lock); - if (buf[0] == 'y' || buf[0] == '\n') { - fputs("** Waawlwalkwwwaa!!\n", stdout); fflush(stdout); - ++comm.msg; - ret = 1; - } - else { - fputs("OK, I hate you. Let me go.\n", stdout); fflush(stdout); - comm.msg = -1; - ret = 0; - } - pthread_mutex_unlock(&comm.lock); - pthread_cond_signal(&comm.cond); - - return ret; -} - -static void *be_stern(void *v __attribute__((unused))) -{ - int msg; - for (;;) { - pthread_mutex_lock(&comm.lock); - while (comm.msg == 0) - pthread_cond_wait(&comm.cond, &comm.lock); - msg = comm.msg; - comm.msg = 0; - pthread_mutex_unlock(&comm.lock); - - if (msg < 0) - break; /* the goofy one learned a lesson! */ - - fputs("I HAVE TO BE STERN WITH YOU!\n", stderr); - fprintf(stderr, "I should give you %d lashes.\n", msg); - sleep(msg); - } - - fputs("You are NOTHING!\n", stderr); - return NULL; -} diff --git a/client/thread_test.c b/client/thread_test.c deleted file mode 100644 index 2900ab712e2..00000000000 --- a/client/thread_test.c +++ /dev/null @@ -1,251 +0,0 @@ -/* Copyright (C) 2000 MySQL 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 */ - -#include <my_global.h> - -#ifndef THREAD - -int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) -{ - printf("This test must be compiled with multithread support to work\n"); - exit(1); -} -#else - -#include <my_sys.h> -#include <my_pthread.h> -#include "mysql.h" -#include <my_getopt.h> - -static my_bool version, verbose, tty_password= 0; -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 my_option my_long_options[] = -{ - {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, - 0, 0, 0, 0, 0}, - {"database", 'D', "Database to use", (gptr*) &database, (gptr*) &database, - 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"host", 'h', "Connect to host", (gptr*) &host, (gptr*) &host, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"password", 'p', - "Password to use when connecting to server. If password is not given it's asked from the tty.", - 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"user", 'u', "User for login if not current user", (gptr*) &user, - (gptr*) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"version", 'V', "Output version information and exit", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"verbose", 'v', "Write some progress indicators", (gptr*) &verbose, - (gptr*) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"query", 'Q', "Query to execute in each threads", (gptr*) &query, - (gptr*) &query, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"port", 'P', "Port number to use for connection", (gptr*) &tcp_port, - (gptr*) &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"socket", 'S', "Socket file to use for connection", (gptr*) &unix_socket, - (gptr*) &unix_socket, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"test-count", 'c', "Run test count times (default %d)", - (gptr*) &number_of_tests, (gptr*) &number_of_tests, 0, GET_UINT, - REQUIRED_ARG, 1000, 0, 0, 0, 0, 0}, - {"thread-count", 't', "Number of threads to start", - (gptr*) &number_of_threads, (gptr*) &number_of_threads, 0, GET_UINT, - REQUIRED_ARG, 2, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 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); - - my_print_help(my_long_options); - print_defaults("my",load_default_groups); - my_print_variables(my_long_options); - 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 my_bool -get_one_option(int optid, const struct my_option *opt __attribute__((unused)), - char *argument) -{ - switch (optid) { - case 'p': - if (argument) - { - my_free(password, MYF(MY_ALLOW_ZERO_PTR)); - password= my_strdup(argument, MYF(MY_FAE)); - while (*argument) *argument++= 'x'; /* Destroy argument */ - } - else - tty_password= 1; - break; - case 'V': - version= 1; - usage(); - exit(0); - break; - case '?': - case 'I': /* Info */ - usage(); - exit(1); - break; - } - return 0; -} - - -static void get_options(int argc, char **argv) -{ - int ho_error; - - load_defaults("my",load_default_groups,&argc,&argv); - - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) - exit(ho_error); - - 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,MY_MUTEX_INIT_FAST); - - 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 */ |