diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/Makefile.am | 5 | ||||
-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 | 1 | ||||
-rw-r--r-- | client/insert_test.c | 2 | ||||
-rw-r--r-- | client/mysql.cc | 517 | ||||
-rw-r--r-- | client/mysqladmin.c | 80 | ||||
-rw-r--r-- | client/mysqlbinlog.cc | 176 | ||||
-rw-r--r-- | client/mysqlcheck.c | 31 | ||||
-rw-r--r-- | client/mysqldump.c | 226 | ||||
-rw-r--r-- | client/mysqlimport.c | 32 | ||||
-rw-r--r-- | client/mysqlshow.c | 32 | ||||
-rw-r--r-- | client/mysqltest.c | 184 | ||||
-rw-r--r-- | client/select_test.c | 1 | ||||
-rw-r--r-- | client/sql_string.cc | 452 | ||||
-rw-r--r-- | client/sql_string.h | 122 |
17 files changed, 1321 insertions, 554 deletions
diff --git a/client/Makefile.am b/client/Makefile.am index 9c994814714..92c46519275 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -16,9 +16,8 @@ # 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 \ diff --git a/client/client_priv.h b/client/client_priv.h index b8181245be2..b6bfc253854 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -37,4 +37,6 @@ enum options { OPT_CHARSETS_DIR=256, OPT_DEFAULT_CHARSET, OPT_SELECT_LIMIT, OPT_MAX_JOIN_SIZE, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER, OPT_SHUTDOWN_TIMEOUT, OPT_LOCAL_INFILE, - 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 }; 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 index fd81ad635ad..e19f83dac92 100644 --- a/client/connect_test.c +++ b/client/connect_test.c @@ -16,6 +16,7 @@ #include <stdio.h> #include <stdlib.h> +#include "my_global.h" #include "mysql.h" static void change_user(MYSQL *sock,const char *user, const char *password, diff --git a/client/insert_test.c b/client/insert_test.c index 42691df6875..e4eb852af52 100644 --- a/client/insert_test.c +++ b/client/insert_test.c @@ -16,6 +16,7 @@ #include <stdio.h> #include <stdlib.h> +#include "my_global.h" #include "mysql.h" #define INSERT_QUERY "insert into test (name,num) values ('item %d', %d)" @@ -33,6 +34,7 @@ int main(int argc, char **argv) exit(1); } + mysql_init(&mysql); 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)); diff --git a/client/mysql.cc b/client/mysql.cc index 5f84261bd82..41da0113670 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -40,7 +40,7 @@ #include <signal.h> #include <violite.h> -const char *VER= "12.18"; +const char *VER= "13.4"; /* Don't try to make a nice table if the data is too big */ #define MAX_COLUMN_LENGTH 1024 @@ -92,7 +92,7 @@ extern "C" { #endif #ifdef FN_NO_CASE_SENCE -#define cmp_database(A,B) my_strcasecmp((A),(B)) +#define cmp_database(A,B) my_strcasecmp(system_charset_info, (A), (B)) #else #define cmp_database(A,B) strcmp((A),(B)) #endif @@ -156,6 +156,11 @@ static FILE *PAGER, *OUTFILE; static MEM_ROOT hash_mem_root; static uint prompt_counter; +#ifdef HAVE_SMEM +static char *shared_memory_base_name=0; +#endif +static uint opt_protocol=0; + #include "sslopt-vars.h" #ifndef DBUG_OFF @@ -194,6 +199,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 +215,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." }, @@ -271,14 +277,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); @@ -350,6 +357,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 +393,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 +438,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); @@ -534,6 +548,8 @@ 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. ", (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -542,6 +558,11 @@ static struct my_option my_long_options[] = 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}, @@ -646,6 +667,16 @@ 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; @@ -708,7 +739,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'W': #ifdef __WIN__ - opt_mysql_unix_port= my_strdup(MYSQL_NAMEDPIPE, MYF(0)); + opt_protocol = MYSQL_PROTOCOL_PIPE; #endif break; #include <sslopt-case.h> @@ -782,9 +813,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) @@ -853,7 +885,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 */ @@ -884,14 +916,14 @@ static COMMANDS *find_command (char *name,char cmd_char) } else { - while (isspace(*name)) + while (my_isspace(system_charset_info,*name)) name++; if (strchr(name,';') || strstr(name,"\\g")) return ((COMMANDS *) 0); if ((end=strcont(name," \t"))) { len=(uint) (end - name); - while (isspace(*end)) + while (my_isspace(system_charset_info,*end)) end++; if (!*end) end=0; // no arguments to function @@ -903,7 +935,8 @@ 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_strncasecmp(system_charset_info,name,commands[i].name,len) && !commands[i].name[len] && (!end || (end && commands[i].takes_params))) || !name && commands[i].cmd_char == cmd_char)) @@ -913,7 +946,8 @@ 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; @@ -931,19 +965,20 @@ 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(system_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(system_charset_info) && + (l = my_ismbchar(system_charset_info, pos, strend))) { while (l--) *out++ = *pos++; pos--; continue; } #endif - if (inchar == '\\') + if (!*ml_comment && inchar == '\\') { // mSQL or postgreSQL style command ? if (!(inchar = (uchar) *++pos)) break; // readline adds one '\' @@ -955,7 +990,7 @@ 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), system_charset_info); buffer.append(tmp); if ((*com->func)(&buffer,pos-1) > 0) return 1; // Quit @@ -977,7 +1012,7 @@ static bool add_line(String &buffer,char *line,char *in_string) continue; } } - else if (inchar == ';' && !*in_string) + else if (!*ml_comment && inchar == ';' && !*in_string) { // ';' is end of command if (out != line) buffer.append(line,(uint) (out-line)); // Add this line @@ -997,17 +1032,33 @@ static bool add_line(String &buffer,char *line,char *in_string) buffer.length(0); out=line; } - else if (!*in_string && (inchar == '#' || - inchar == '-' && pos[1] == '-' && - isspace(pos[2]))) + else if (!*ml_comment && (!*in_string && (inchar == '#' || + inchar == '-' && pos[1] == '-' && + my_isspace(system_charset_info,pos[2])))) break; // comment to end of line + else if (!*in_string && inchar == '/' && *(pos+1) == '*') + { + pos++; + *ml_comment= 1; + if (out != line) + { + buffer.append(line,(uint) (out-line)); + out=line; + } + } + else if (*ml_comment && !*in_string && 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 == '"')) *in_string=(char) inchar; - *out++ = (char) inchar; + if (!(*ml_comment)) + *out++ = (char) inchar; } } if (out != line || !buffer.is_empty()) @@ -1016,7 +1067,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; @@ -1028,8 +1079,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 @@ -1037,8 +1088,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 */ } @@ -1049,9 +1103,16 @@ 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) + 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 } /* @@ -1061,17 +1122,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; @@ -1250,7 +1315,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))) { @@ -1270,7 +1335,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++; } @@ -1326,31 +1391,150 @@ 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; + uint error=put_info(mysql_error(&mysql),INFO_ERROR, mysql_errno(&mysql)); + if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 || + status.batch) + 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_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql)); + + return 0; +} + + +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; + 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)))) + return error; + if ((error= mysql_store_result_for_lazy(&result))) + return error; + + if (result) + { + ulonglong num_rows= mysql_num_rows(result); + if (num_rows == 1) + { + if (!(cur= mysql_fetch_row(result))) + { + error= -1; + goto err; + } + + init_pager(); + if (cur[1][0] == 'Y') + { + tee_fprintf(PAGER, "Help topic \'%s\'\n", cur[0]); + tee_fprintf(PAGER, "%s\n", cur[2]); + tee_fprintf(PAGER, "For help on specific function please type 'help <function>'\nwhere function is one of next:\n%s\n", cur[3]); + } + else + { + tee_fprintf(PAGER, "Name: \'%s\'\n\n", cur[0]); + tee_fprintf(PAGER, "Description:\n%s\n\n", cur[2]); + if (cur[3]) + tee_fprintf(PAGER, "Examples:\n%s\n", cur[3]); + } + end_pager(); + } + else if (num_rows > 1) + { + 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); + + init_pager(); + char last_char= '_'; + while ((cur= mysql_fetch_row(result))) + { + if (cur[1][0]!=last_char) + { + put_info("-------------------------------------------", INFO_INFO); + put_info(cur[1][0] == 'Y' ? + "categories:" : "functions:", INFO_INFO); + put_info("-------------------------------------------", INFO_INFO); + } + last_char= cur[1][0]; + tee_fprintf(PAGER, "%s\n", cur[0]); + } + tee_fprintf(PAGER, "\n"); + end_pager(); + } + else + { + put_info("\nNothing found\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,' '); - 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); - for (i = 0; commands[i].name; i++) + if (help_arg) { - if (commands[i].func) - tee_fprintf(stdout, "%s\t(\\%c)\t%s\n", commands[i].name, - commands[i].cmd_char, commands[i].doc); + return com_server_help(buffer,line,help_arg+1); } - if (connected) - tee_fprintf(stdout, - "\nConnection id: %ld (Can be used with mysqladmin kill)\n\n", - mysql_thread_id(&mysql)); else - tee_fprintf(stdout, "Not connected! Reconnect with 'connect'!\n\n"); + { + 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("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 && mysql_get_server_version(&mysql) >= 40100) + put_info("\nFor server side help, type 'help all'\n", INFO_INFO); return 0; } @@ -1375,9 +1559,9 @@ 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; + ulong timer, warnings; uint error=0; if (!status.batch) @@ -1406,30 +1590,23 @@ com_go(String *buffer,char *line __attribute__((unused))) (void) com_print(buffer,0); if (skip_updates && - (buffer->length() < 4 || my_sortcmp(buffer->ptr(),"SET ",4))) + (buffer->length() < 4 || my_strnncoll(system_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); @@ -1442,13 +1619,9 @@ com_go(String *buffer,char *line __attribute__((unused))) } else { - if (!(result=mysql_store_result(&mysql))) - { - 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) @@ -1459,7 +1632,7 @@ com_go(String *buffer,char *line __attribute__((unused))) { if (!mysql_num_rows(result) && ! quick) { - sprintf(buff,"Empty set%s",time_buff); + strmov(buff, "Empty set"); } else { @@ -1474,20 +1647,30 @@ com_go(String *buffer,char *line __attribute__((unused))) print_tab_data(result); else print_table_data(result); - sprintf(buff,"%ld %s in set%s", + sprintf(buff,"%ld %s in set", (long) mysql_num_rows(result), - (long) mysql_num_rows(result) == 1 ? "row" : "rows", - time_buff); + (long) mysql_num_rows(result) == 1 ? "row" : "rows"); end_pager(); } } else if (mysql_affected_rows(&mysql) == ~(ulonglong) 0) - sprintf(buff,"Query OK%s",time_buff); + strmov(buff,"Query OK"); else - sprintf(buff,"Query OK, %ld %s affected%s", + sprintf(buff,"Query OK, %ld %s affected", (long) mysql_affected_rows(&mysql), - (long) mysql_affected_rows(&mysql) == 1 ? "row" : "rows", - time_buff); + (long) mysql_affected_rows(&mysql) == 1 ? "row" : "rows"); + + pos=strend(buff); + if ((warnings= mysql_warning_count(&mysql))) + { + *pos++= ','; + *pos++= ' '; + pos=int2str(warnings, pos, 10); + pos=strmov(pos, " warning"); + if (warnings != 1) + *pos++= 's'; + } + strmov(pos, time_buff); put_info(buff,INFO_RESULT); if (mysql_info(&mysql)) put_info(mysql_info(&mysql),INFO_RESULT); @@ -1598,10 +1781,10 @@ print_table_data(MYSQL_RES *result) print_field_types(result); mysql_field_seek(result,0); } - separator.copy("+",1); + separator.copy("+",1,system_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 @@ -1743,7 +1926,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; @@ -1812,8 +1995,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(system_charset_info) && + (l = my_ismbchar(system_charset_info, pos, end))) + { while (l--) tee_putc(*pos++, PAGER); pos--; @@ -1873,7 +2057,7 @@ com_tee(String *buffer, char *line __attribute__((unused))) if (status.batch) return 0; - while (isspace(*line)) + while (my_isspace(system_charset_info,*line)) line++; if (!(param = strchr(line, ' '))) // if outfile wasn't given, use the default { @@ -1892,11 +2076,12 @@ com_tee(String *buffer, char *line __attribute__((unused))) } /* eliminate the spaces before the parameters */ - while (isspace(*param)) + while (my_isspace(system_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(system_charset_info,end[-1]) || + my_iscntrl(system_charset_info,end[-1]))) end--; end[0]= 0; if (end == file_name) @@ -1932,7 +2117,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(system_charset_info,*line)) line++; if (!(param= strchr(line, ' '))) // if pager was not given, use the default { @@ -1948,10 +2133,11 @@ com_pager(String *buffer, char *line __attribute__((unused))) } else { - while (isspace(*param)) + while (my_isspace(system_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(system_charset_info,end[-1]) || + my_iscntrl(system_charset_info,end[-1]))) end--; end[0]=0; strmov(pager, pager_name); @@ -2085,23 +2271,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)); @@ -2137,15 +2321,16 @@ static int com_source(String *buffer, char *line) FILE *sql_file; /* Skip space from file name */ - while (isspace(*line)) + while (my_isspace(system_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(system_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(system_charset_info,end[-1]) || + my_iscntrl(system_charset_info,end[-1]))) end--; end[0]=0; unpack_filename(source_name,source_name); @@ -2186,18 +2371,15 @@ 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(current_db, tmp)) { if (one_database) skip_updates= 1; @@ -2233,6 +2415,74 @@ 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; + my_bool quoted= 0, valid_arg= 0; + uint count= 0; + char qtype= 0; + + ptr= line; + if (get_next_arg) + { + for (; ptr && *ptr; ptr++); + if ((ptr + 1) && *(ptr + 1)) + ptr++; + } + else + { + /* skip leading white spaces */ + while (my_isspace(system_charset_info, *ptr)) + ptr++; + if (*ptr == '\\') // short command was used + ptr+= 2; + while (!my_isspace(system_charset_info, *ptr)) // skip command + ptr++; + } + while (my_isspace(system_charset_info, *ptr)) + ptr++; + if (*ptr == '\'' || *ptr == '\"' || *ptr == '`') + { + qtype= *ptr; + quoted= 1; + ptr++; + } + for (; ptr && *ptr; ptr++, count++) + { + if (*ptr == '\\') // escaped character + { + // jump over the backslash + char *tmp_ptr, tmp_buff[256]; + tmp_ptr= strmov(tmp_buff, (ptr - count)); + tmp_ptr-= (strlen(tmp_buff) - count); + strmov(tmp_ptr, (ptr + 1)); + strmov(line, tmp_buff); + ptr= line; + ptr+= count; + } + else if ((!quoted && *ptr == ' ') || (quoted && *ptr == qtype)) + { + *ptr= 0; + break; + } + } + for (ptr-= count; ptr && *ptr; ptr++) + if (!my_isspace(system_charset_info, *ptr)) + valid_arg= 1; + return valid_arg ? ptr - count : '\0'; +} + + static int sql_real_connect(char *host,char *database,char *user,char *password, uint silent) @@ -2255,6 +2505,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]; @@ -2278,7 +2534,9 @@ sql_real_connect(char *host,char *database,char *user,char *password, 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 @@ -2370,14 +2628,16 @@ com_status(String *buffer __attribute__((unused)), 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); + system_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]) { @@ -2479,7 +2739,7 @@ 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(system_charset_info,end[-1])) end--; buffer.length((uint) (end-start)); } @@ -2643,14 +2903,16 @@ static const char* construct_prompt() break; } case 'p': +#ifndef EMBEDDED_LIBRARY 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) @@ -2791,3 +3053,4 @@ void sql_element_free(void *ptr) my_free((gptr) ptr,MYF(0)); } #endif /* EMBEDDED_LIBRARY */ + diff --git a/client/mysqladmin.c b/client/mysqladmin.c index 95bc17e880b..cba137d54c6 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 }; @@ -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,6 +150,11 @@ 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}, +#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.", @@ -159,7 +172,7 @@ static struct my_option my_long_options[] = (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, 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}, @@ -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--) { @@ -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") || @@ -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,9 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) return 1; } if (argv[1][0]) - make_scrambled_password(crypted_pw,argv[1]); + make_scrambled_password(crypted_pw,argv[1], + (find_type(argv[0], &command_typelib, 2) == + ADMIN_OLD_PASSWORD), &rand_st); else crypted_pw[0]=0; /* No password */ sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw); @@ -837,7 +876,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 +1035,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 4cf86eb31c7..83c93ee3fca 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -18,6 +18,7 @@ #undef MYSQL_SERVER #include "client_priv.h" #include <time.h> +#include <assert.h> #include "log_event.h" #define BIN_LOG_HEADER_SIZE 4 @@ -56,6 +57,9 @@ static short binlog_flags = 0; static MYSQL* mysql = NULL; static const char* table = 0; +static bool use_local_load= 0; +static const char* dirname_for_local_load= 0; + static void dump_local_log_entries(const char* logname); static void dump_remote_log_entries(const char* logname); static void dump_log_entries(const char* logname); @@ -64,6 +68,128 @@ static void dump_remote_table(NET* net, const char* db, const char* table); static void die(const char* fmt, ...); static MYSQL* safe_connect(); +class Load_log_processor +{ + char target_dir_name[MY_NFILE]; + int target_dir_name_len; + DYNAMIC_ARRAY file_names; + + const char* create_file(Create_file_log_event *ce) + { + const char *bname= ce->fname + ce->fname_len -1; + while (bname>ce->fname && bname[-1]!=FN_LIBCHAR) + bname--; + + uint blen= ce->fname_len - (bname-ce->fname); + uint full_len= target_dir_name_len + blen; + char *tmp; + if (!(tmp= my_malloc(full_len + 9 + 1,MYF(MY_WME))) || + set_dynamic(&file_names,(gptr)&ce,ce->file_id)) + { + die("Could not construct local filename %s%s",target_dir_name,bname); + return 0; + } + + char *ptr= tmp; + memcpy(ptr,target_dir_name,target_dir_name_len); + ptr+= target_dir_name_len; + memcpy(ptr,bname,blen); + ptr+= blen; + sprintf(ptr,"-%08x",ce->file_id); + + ce->set_fname_outside_temp_buf(tmp,full_len); + + return tmp; + } + + void append_to_file(const char* fname, int flags, + gptr data, uint size) + { + File file; + if ((file= my_open(fname,flags,MYF(MY_WME)) < 0) || + my_write(file,(byte*) data,size,MYF(MY_WME|MY_NABP)) || + my_close(file,MYF(MY_WME))) + exit(1); + } + +public: + + Load_log_processor() + { + init_dynamic_array(&file_names,sizeof(Create_file_log_event*), + 100,100 CALLER_INFO); + } + + ~Load_log_processor() + { + destroy(); + delete_dynamic(&file_names); + } + + void init_by_dir_name(const char *atarget_dir_name) + { + char *end= strmov(target_dir_name,atarget_dir_name); + if (end[-1]!=FN_LIBCHAR) + *end++= FN_LIBCHAR; + target_dir_name_len= end-target_dir_name; + } + void init_by_file_name(const char *file_name) + { + int len= strlen(file_name); + const char *end= file_name + len - 1; + while (end>file_name && *end!=FN_LIBCHAR) + end--; + if (*end!=FN_LIBCHAR) + target_dir_name_len= 0; + else + { + target_dir_name_len= end - file_name + 1; + memmove(target_dir_name,file_name,target_dir_name_len); + } + } + void init_by_cur_dir() + { + target_dir_name_len= 0; + } + void destroy() + { + Create_file_log_event **ptr= (Create_file_log_event**)file_names.buffer; + Create_file_log_event **end= ptr + file_names.elements; + for (; ptr<end; ptr++) + { + if (*ptr) + { + my_free((char*)(*ptr)->fname,MYF(MY_WME)); + delete *ptr; + *ptr= 0; + } + } + } + Create_file_log_event *grab_event(uint file_id) + { + Create_file_log_event **ptr= + (Create_file_log_event**)file_names.buffer + file_id; + Create_file_log_event *res= *ptr; + *ptr= 0; + return res; + } + void process(Create_file_log_event *ce) + { + const char *fname= create_file(ce); + append_to_file(fname,O_CREAT|O_BINARY,ce->block,ce->block_len); + } + void process(Append_block_log_event *ae) + { + if (ae->file_id >= file_names.elements) + die("Skiped CreateFile event for file_id: %u",ae->file_id); + Create_file_log_event* ce= + *((Create_file_log_event**)file_names.buffer + ae->file_id); + append_to_file(ce->fname,O_APPEND|O_BINARY,ae->block,ae->block_len); + } +}; + +Load_log_processor load_processor; + static struct my_option my_long_options[] = { #ifndef DBUG_OFF @@ -97,6 +223,9 @@ static struct my_option my_long_options[] = {"user", 'u', "Connect to the remote server as username", (gptr*) &user, (gptr*) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"local-load", 'l', "Prepare files for local load in directory", + (gptr*) &dirname_for_local_load, (gptr*) &dirname_for_local_load, 0, + GET_STR_ALLOC, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Print version and exit.", 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} @@ -209,6 +338,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'V': print_version(); exit(0); + case 'l': + use_local_load= 1; + break; case '?': usage(); exit(0); @@ -420,6 +552,8 @@ static void dump_local_log_entries(const char* logname) MYF(MY_WME | MY_NABP))) exit(1); old_format = check_header(file); + if (use_local_load && !dirname_for_local_load) + load_processor.init_by_file_name(logname); } else { @@ -441,6 +575,8 @@ static void dump_local_log_entries(const char* logname) } file->pos_in_file=position; file->seek_not_done=0; + if (use_local_load && !dirname_for_local_load) + load_processor.init_by_cur_dir(); } if (!position) @@ -495,11 +631,43 @@ Could not read entry at offset %s : Error in log format or read error", } if (!short_form) fprintf(result_file, "# at %s\n",llstr(old_off,llbuff)); - - ev->print(result_file, short_form, last_db); + + if (!use_local_load) + ev->print(result_file, short_form, last_db); + else + { + switch(ev->get_type_code()) + { + case CREATE_FILE_EVENT: + { + Create_file_log_event* ce= (Create_file_log_event*)ev; + ce->print(result_file, short_form, last_db,true); + load_processor.process(ce); + ev= 0; + break; + } + case APPEND_BLOCK_EVENT: + ev->print(result_file, short_form, last_db); + load_processor.process((Append_block_log_event*)ev); + break; + case EXEC_LOAD_EVENT: + { + ev->print(result_file, short_form, last_db); + Execute_load_log_event *exv= (Execute_load_log_event*)ev; + Create_file_log_event *ce= load_processor.grab_event(exv->file_id); + ce->print(result_file, short_form, last_db,true); + my_free((char*)ce->fname,MYF(MY_WME)); + delete ce; + break; + } + default: + ev->print(result_file, short_form, last_db); + } + } } rec_count++; - delete ev; + if (ev) + delete ev; } if (fd >= 0) my_close(fd, MYF(MY_WME)); @@ -520,6 +688,8 @@ int main(int argc, char** argv) if (use_remote) mysql = safe_connect(); + if (dirname_for_local_load) + load_processor.init_by_dir_name(dirname_for_local_load); if (table) { diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 3261ec1577d..cd67a2c7522 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -41,6 +41,10 @@ static char *opt_password = 0, *current_user = 0, *default_charset = 0, *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; enum operations {DO_CHECK, DO_REPAIR, DO_ANALYZE, DO_OPTIMIZE}; @@ -109,6 +113,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 +122,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 +249,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 +263,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; } @@ -582,6 +602,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 +695,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 da02c49dd69..908bdc5b51e 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -36,7 +36,7 @@ ** Added --single-transaction option 06/06/2002 by Peter Zaitsev */ -#define DUMP_VERSION "9.07" +#define DUMP_VERSION "10.0" #include <my_global.h> #include <my_sys.h> @@ -69,27 +69,45 @@ 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, +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_autocommit=0,opt_master_data,opt_disable_keys=0,opt_xml=0, + opt_autocommit=0,opt_master_data,opt_disable_keys=1,opt_xml=0, tty_password=0,opt_single_transaction=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, *default_charset, *opt_compatible_mode_str= 0, + *err_ptr= 0; +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; + +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[] = { @@ -98,13 +116,13 @@ 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, @@ -112,6 +130,10 @@ static struct my_option my_long_options[] = {"character-sets-dir", OPT_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.", @@ -131,11 +153,11 @@ static struct my_option my_long_options[] = 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}, @@ -164,7 +186,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}, @@ -174,8 +196,8 @@ 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.}", (gptr*) &opt_create_db, (gptr*) &opt_create_db, 0, GET_BOOL, NO_ARG, 0, 0, @@ -188,7 +210,7 @@ static struct my_option my_long_options[] = "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.", @@ -200,14 +222,24 @@ 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', "Don't buffer query, dump directly to stdout.", - (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"quote-names",'Q', "Quote table and column names with a `", (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}, @@ -311,6 +343,7 @@ static void write_header(FILE *sql_file, char *db_name) return; } /* write_header */ + static void write_footer(FILE *sql_file) { if (opt_xml) @@ -318,6 +351,7 @@ static void write_footer(FILE *sql_file) fputs("\n", sql_file); } /* write_footer */ + static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) @@ -347,7 +381,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': @@ -367,18 +401,48 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), 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_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; @@ -398,13 +462,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); @@ -483,6 +542,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))) @@ -527,7 +592,7 @@ 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(system_charset_info,*str) && *str != '$') return 1; #endif return 0; @@ -578,6 +643,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, "\" */"); + 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`",table); if (mysql_query(sock, buff)) { @@ -1045,7 +1135,8 @@ static void dumpTable(uint numFields, char *table) /* change any strings ("inf","nan",..) into NULL */ char *ptr = row[i]; dynstr_append(&extended_row, - (!isalpha(*ptr)) ? ptr : "NULL"); + (!my_isalpha(system_charset_info,*ptr)) ? + ptr : "NULL"); } } else @@ -1077,9 +1168,11 @@ static void dumpTable(uint numFields, char *table) 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"); + field->name, + !my_isalpha(system_charset_info, *ptr) ? ptr: "NULL"); else - fputs((!isalpha(*ptr)) ? ptr : "NULL", md_result_file); + fputs((!my_isalpha(system_charset_info,*ptr)) ? + ptr : "NULL", md_result_file); } } else @@ -1248,8 +1341,28 @@ static int init_dumping(char *database) { fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", database); if (!opt_create_db) - fprintf(md_result_file,"\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", + { + char qbuf[128]; + MYSQL_ROW row; + MYSQL_RES *dbinfo; + + sprintf(qbuf,"SHOW CREATE DATABASE WITH IF NOT EXISTS %s",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", database); + } + 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", database); } } @@ -1350,6 +1463,48 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } /* 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(system_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, @@ -1460,6 +1615,9 @@ int main(int argc, char **argv) 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 diff --git a/client/mysqlimport.c b/client/mysqlimport.c index a11b7383517..408a5873589 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -49,6 +49,11 @@ static my_string opt_mysql_unix_port=0; static my_string opt_ignore_lines=0; #include <sslopt-vars.h> +#ifdef HAVE_SMEM +static char *shared_memory_base_name=0; +#endif +static uint opt_protocol=0; + static struct my_option my_long_options[] = { {"character-sets-dir", OPT_CHARSETS_DIR, @@ -112,8 +117,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 +193,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; @@ -352,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))) @@ -486,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/mysqlshow.c b/client/mysqlshow.c index 0b47e06534f..e6e21f177ef 100644 --- a/client/mysqlshow.c +++ b/client/mysqlshow.c @@ -31,6 +31,11 @@ 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; +#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; static int list_dbs(MYSQL *mysql,const char *wild); @@ -104,6 +109,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 (!(mysql_real_connect(&mysql,host,user,opt_password, (first_argument_uses_wildcards) ? "" : argv[0],opt_mysql_port,opt_mysql_unix_port, 0))) @@ -131,6 +142,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 */ @@ -165,6 +179,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}, @@ -230,9 +251,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; diff --git a/client/mysqltest.c b/client/mysqltest.c index cad13fe1349..f417018dbb7 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -166,7 +166,8 @@ typedef struct VAR var_reg[10]; /*Perl/shell-like variable registers */ HASH var_hash; -int disable_query_log=0, disable_result_log=0; +my_bool disable_query_log=0, disable_result_log=0, disable_warnings=0; +my_bool disable_info= 1; /* By default off */ struct connection cons[MAX_CONS]; struct connection* cur_con, *next_con, *cons_end; @@ -195,6 +196,8 @@ Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG, Q_SERVER_START, Q_SERVER_STOP,Q_REQUIRE_MANAGER, Q_WAIT_FOR_SLAVE_TO_STOP, Q_REQUIRE_VERSION, +Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS, +Q_ENABLE_INFO, Q_DISABLE_INFO, Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ Q_COMMENT_WITH_COMMAND @@ -253,6 +256,10 @@ const char *command_names[]= "require_manager", "wait_for_slave_to_stop", "require_version", + "enable_warnings", + "disable_warnings", + "enable_info", + "diable_info", 0 }; @@ -311,7 +318,7 @@ static int eval_result = 0; 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 #define MAX_SERVER_ARGS 20 @@ -482,9 +489,9 @@ void init_parser() int hex_val(int c) { - if (isdigit(c)) + if (my_isdigit(system_charset_info,c)) return c - '0'; - else if ((c = tolower(c)) >= 'a' && c <= 'f') + else if ((c = my_tolower(system_charset_info,c)) >= 'a' && c <= 'f') return c - 'a' + 10; else return -1; @@ -594,7 +601,7 @@ VAR* var_get(const char* var_name, const char** var_name_end, my_bool raw, { const char* save_var_name = var_name, *end; end = (var_name_end) ? *var_name_end : 0; - while (isvar(*var_name) && var_name != end) + while (my_isvar(system_charset_info,*var_name) && var_name != end) ++var_name; if (var_name == save_var_name) { @@ -745,7 +752,7 @@ int do_server_op(struct st_query* q,const char* op) com_p=strmov(com_p,"_exec "); if (!*p) die("Missing server name in server_%s\n",op); - while (*p && !isspace(*p)) + while (*p && !my_isspace(system_charset_info,*p)) { *com_p++=*p++; } @@ -778,7 +785,7 @@ int do_require_version(struct st_query* q) if (!*p) die("Missing version argument in require_version\n"); ver_arg = p; - while (*p && !isspace(*p)) + while (*p && !my_isspace(system_charset_info,*p)) p++; *p = 0; ver_arg_len = p - ver_arg; @@ -808,7 +815,7 @@ int do_source(struct st_query* q) if (!*p) die("Missing file name in source\n"); name = p; - while (*p && !isspace(*p)) + while (*p && !my_isspace(system_charset_info,*p)) p++; *p = 0; @@ -1045,11 +1052,11 @@ int do_let(struct st_query* q) if (!*p) die("Missing variable name in let\n"); var_name = p; - while (*p && (*p != '=' || isspace(*p))) + while (*p && (*p != '=' || my_isspace(system_charset_info,*p))) p++; var_name_end = p; if (*p == '=') p++; - while (*p && isspace(*p)) + while (*p && my_isspace(system_charset_info,*p)) p++; var_val_start = p; return var_set(var_name, var_name_end, var_val_start, q->end); @@ -1078,8 +1085,8 @@ int do_disable_rpl_parse(struct st_query* q __attribute__((unused))) int do_sleep(struct st_query* q, my_bool real_sleep) { - char* p=q->first_argument; - while (*p && isspace(*p)) + char *p=q->first_argument; + while (*p && my_isspace(system_charset_info,*p)) p++; if (!*p) die("Missing argument in sleep\n"); @@ -1095,7 +1102,7 @@ static void get_file_name(char *filename, struct st_query* q) char* p=q->first_argument; strnmov(filename, p, FN_REFLEN); /* Remove end space */ - while (p > filename && isspace(p[-1])) + while (p > filename && my_isspace(system_charset_info,p[-1])) p--; p[0]=0; } @@ -1181,7 +1188,7 @@ static char *get_string(char **to_ptr, char **from_ptr, if (*from != ' ' && *from) die("Wrong string argument in %s\n", q->query); - while (isspace(*from)) /* Point to next string */ + while (my_isspace(system_charset_info,*from)) /* Point to next string */ from++; *to =0; /* End of string marker */ @@ -1238,8 +1245,8 @@ static void get_replace(struct st_query *q) insert_pointer_name(&to_array,to); } for (i=1,pos=word_end_chars ; i < 256 ; i++) - if (isspace(i)) - *pos++=i; + if (my_isspace(system_charset_info,i)) + *pos++= i; *pos=0; /* End pointer */ if (!(glob_replace=init_replace((char**) from_array.typelib.type_names, (char**) to_array.typelib.type_names, @@ -1275,7 +1282,7 @@ int select_connection(char *p) if (!*p) die("Missing connection name in connect\n"); name = p; - while (*p && !isspace(*p)) + while (*p && !my_isspace(system_charset_info,*p)) p++; *p = 0; @@ -1301,7 +1308,7 @@ int close_connection(struct st_query* q) if (!*p) die("Missing connection name in connect\n"); name = p; - while (*p && !isspace(*p)) + while (*p && !my_isspace(system_charset_info,*p)) p++; *p = 0; @@ -1309,6 +1316,7 @@ int close_connection(struct st_query* q) { if (!strcmp(con->name, name)) { +#ifndef EMBEDDED_LIBRARY if (q->type == Q_DIRTY_CLOSE) { if (con->mysql.net.vio) @@ -1317,7 +1325,7 @@ int close_connection(struct st_query* q) con->mysql.net.vio = 0; } } - +#endif mysql_close(&con->mysql); DBUG_RETURN(0); } @@ -1337,11 +1345,13 @@ int close_connection(struct st_query* q) char* safe_get_param(char* str, char** arg, const char* msg) { DBUG_ENTER("safe_get_param"); - while (*str && isspace(*str)) str++; + while (*str && my_isspace(system_charset_info,*str)) + str++; *arg = str; for (; *str && *str != ',' && *str != ')' ; str++) { - if (isspace(*str)) *str = 0; + if (my_isspace(system_charset_info,*str)) + *str = 0; } if (!*str) die(msg); @@ -1623,7 +1633,7 @@ int read_line(char* buf, int size) { state = R_COMMENT; } - else if (isspace(c)) + else if (my_isspace(system_charset_info,c)) { if (c == '\n') start_lineno= ++*lineno; /* Query hasn't started yet */ @@ -1749,7 +1759,7 @@ int read_query(struct st_query** q_ptr) { expected_errno = 0; p++; - for (;isdigit(*p);p++) + for (;my_isdigit(system_charset_info,*p);p++) expected_errno = expected_errno * 10 + *p - '0'; q->expected_errno[0] = expected_errno; q->expected_errno[1] = 0; @@ -1757,25 +1767,28 @@ int read_query(struct st_query** q_ptr) } } - while (*p && isspace(*p)) p++ ; + while (*p && my_isspace(system_charset_info,*p)) + p++ ; if (*p == '@') { p++; p1 = q->record_file; - while (!isspace(*p) && + while (!my_isspace(system_charset_info,*p) && p1 < q->record_file + sizeof(q->record_file) - 1) *p1++ = *p++; *p1 = 0; } } - while (*p && isspace(*p)) p++; + while (*p && my_isspace(system_charset_info,*p)) + p++; 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 && !isspace(*p) ; p++) ; + for (p=q->query; *p && !my_isspace(system_charset_info,*p) ; p++) ; q->first_word_len = (uint) (p - q->query); - while (*p && isspace(*p)) p++; + while (*p && my_isspace(system_charset_info,*p)) + p++; q->first_argument=p; q->end = strend(q->query); parser.read_lines++; @@ -2024,6 +2037,36 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, dynstr_append_mem(ds, val, len); } +/* + Append all results to the dynamic string separated with '\t' +*/ + +static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) +{ + MYSQL_ROW row; + int num_fields= mysql_num_fields(res); + unsigned long *lengths; + while ((row = mysql_fetch_row(res))) + { + int i; + lengths = mysql_fetch_lengths(res); + for (i = 0; i < num_fields; i++) + { + const char *val= row[i]; + ulonglong len= lengths[i]; + if (!val) + { + val = "NULL"; + len = 4; + } + if (i) + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, val, len); + } + dynstr_append_mem(ds, "\n", 1); + } +} + /* * flags control the phased/stages of query execution to be performed @@ -2034,12 +2077,7 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, int run_query(MYSQL* mysql, struct st_query* q, int flags) { MYSQL_RES* res = 0; - MYSQL_FIELD* fields; - MYSQL_ROW row; - int num_fields,i, error = 0; - unsigned long* lengths; - char* val; - int len; + int i, error = 0; DYNAMIC_STRING *ds; DYNAMIC_STRING ds_tmp; DYNAMIC_STRING eval_query; @@ -2127,17 +2165,17 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) 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 + 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)); + mysql_errno(mysql)); error = 1; goto end; - }*/ + }*/ } if (q->expected_errno[0]) @@ -2148,45 +2186,52 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) goto end; } - if (!res) - goto end; - if (!disable_result_log) { - fields = mysql_fetch_fields(res); - num_fields = mysql_num_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); - } - - dynstr_append_mem(ds, "\n", 1); - - while ((row = mysql_fetch_row(res))) - { - lengths = mysql_fetch_lengths(res); + int num_fields= mysql_num_fields(res); + MYSQL_FIELD *fields= mysql_fetch_fields(res); for (i = 0; i < num_fields; i++) { - val = (char*)row[i]; - len = lengths[i]; - - if (!val) - { - val = (char*)"NULL"; - len = 4; - } - if (i) dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append_mem(ds, val, len); + dynstr_append(ds, fields[i].name); + } + dynstr_append_mem(ds, "\n", 1); + append_result(ds, res); + } + + /* 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) @@ -2298,7 +2343,8 @@ static void init_var_hash() { VAR* v; DBUG_ENTER("init_var_hash"); - if (hash_init(&var_hash, 1024, 0, 0, get_var_key, var_free, MYF(0))) + if (hash_init(&var_hash, system_charset_info, + 1024, 0, 0, get_var_key, var_free, MYF(0))) die("Variable hash initialization failed"); var_from_env("MASTER_MYPORT", "9306"); var_from_env("SLAVE_MYPORT", "9307"); @@ -2391,6 +2437,10 @@ int main(int argc, char** argv) case Q_DISABLE_QUERY_LOG: disable_query_log=1; break; case Q_ENABLE_RESULT_LOG: disable_result_log=0; break; case Q_DISABLE_RESULT_LOG: disable_result_log=1; break; + case Q_ENABLE_WARNINGS: disable_warnings=0; break; + case Q_DISABLE_WARNINGS: disable_warnings=1; break; + case Q_ENABLE_INFO: disable_info=0; break; + case Q_DISABLE_INFO: disable_info=1; break; case Q_SOURCE: do_source(q); break; case Q_SLEEP: do_sleep(q, 0); break; case Q_REAL_SLEEP: do_sleep(q, 1); break; diff --git a/client/select_test.c b/client/select_test.c index ee2a9192865..d7f18c0f1f0 100644 --- a/client/select_test.c +++ b/client/select_test.c @@ -19,6 +19,7 @@ #endif #include <stdio.h> #include <stdlib.h> +#include "my_global.h" #include "mysql.h" #define SELECT_QUERY "select name from test where num = %d" diff --git a/client/sql_string.cc b/client/sql_string.cc index 3c5e481eaad..8ab205d9fb1 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->snprintf == my_snprintf_8bit) + { + str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr); + } + else + { + str_length=cs->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->snprintf == my_snprintf_8bit) + { + str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr); + } + else + { + str_length=cs->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->mb_wc(from,&wc,s,se)) > 0 ) + { + s+=cnvres; + } + else if (cnvres==MY_CS_ILSEQ) + { + s++; + wc='?'; + } + else + break; + +outp: + if((cnvres=to->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..42f9e446981 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=default_charset_info; + } 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=default_charset_info; + } + 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]; } @@ -76,28 +101,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 +152,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 +176,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 +201,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); }; |