diff options
42 files changed, 1195 insertions, 337 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index fff7224afd6..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 diff --git a/include/config-win.h b/include/config-win.h index efe226b2381..172209a210c 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -16,6 +16,12 @@ /* Defines for Win32 to make it compatible for MySQL */ +#ifdef __WIN2000__ +/* We have to do this define before including windows.h to get the AWE API +functions */ +#define _WIN32_WINNT 0x0500 +#endif + #include <sys/locking.h> #include <windows.h> #include <math.h> /* Because of rint() */ diff --git a/include/m_ctype.h b/include/m_ctype.h index 5cc934eb7cf..4ed5c6eec6a 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -92,6 +92,8 @@ typedef struct charset_info_st uint strxfrm_multiply; int (*strnncoll)(struct charset_info_st *, const uchar *, uint, const uchar *, uint); + int (*strnncollsp)(struct charset_info_st *, + const uchar *, uint, const uchar *, uint); int (*strnxfrm)(struct charset_info_st *, uchar *, uint, const uchar *, uint); my_bool (*like_range)(struct charset_info_st *, @@ -110,6 +112,8 @@ typedef struct charset_info_st int (*ismbchar)(struct charset_info_st *, const char *, const char *); my_bool (*ismbhead)(struct charset_info_st *, uint); int (*mbcharlen)(struct charset_info_st *, uint); + uint (*numchars)(struct charset_info_st *, const char *b, const char *e); + uint (*charpos)(struct charset_info_st *, const char *b, const char *e, uint pos); /* Unicode convertion */ int (*mb_wc)(struct charset_info_st *cs,my_wc_t *wc, @@ -189,6 +193,9 @@ extern int my_strnxfrm_simple(CHARSET_INFO *, uchar *, uint, const uchar *, extern int my_strnncoll_simple(CHARSET_INFO *, const uchar *, uint, const uchar *, uint); +extern int my_strnncollsp_simple(CHARSET_INFO *, const uchar *, uint, + const uchar *, uint); + extern uint my_hash_caseup_simple(CHARSET_INFO *cs, const byte *key, uint len); @@ -247,6 +254,9 @@ int my_wildcmp_8bit(CHARSET_INFO *, const char *wildstr,const char *wildend, int escape, int w_one, int w_many); +uint my_numchars_8bit(CHARSET_INFO *, const char *b, const char *e); +uint my_charpos_8bit(CHARSET_INFO *, const char *b, const char *e, uint pos); + #ifdef USE_MB /* Functions for multibyte charsets */ @@ -261,6 +271,9 @@ int my_wildcmp_mb(CHARSET_INFO *, const char *str,const char *str_end, const char *wildstr,const char *wildend, int escape, int w_one, int w_many); +uint my_numchars_mb(CHARSET_INFO *, const char *b, const char *e); +uint my_charpos_mb(CHARSET_INFO *, const char *b, const char *e, uint pos); + #endif #define _U 01 /* Upper case */ diff --git a/include/my_sys.h b/include/my_sys.h index 4f41f6eeb94..9a688ea6e78 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -706,6 +706,7 @@ extern void freeze_size(DYNAMIC_ARRAY *array); #define dynamic_array_ptr(array,array_index) ((array)->buffer+(array_index)*(array)->size_of_element) #define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index)) #define push_dynamic(A,B) insert_dynamic(A,B) +#define reset_dynamic(array) ((array)->elements= 0) extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, uint init_alloc,uint alloc_increment); diff --git a/innobase/include/os0proc.h b/innobase/include/os0proc.h index 3d752df43a6..664952bd166 100644 --- a/innobase/include/os0proc.h +++ b/innobase/include/os0proc.h @@ -16,7 +16,7 @@ typedef void* os_process_t; typedef unsigned long int os_process_id_t; /* The cell type in os_awe_allocate_mem page info */ -#if defined(__NT__) && defined(ULONG_PTR) +#if defined(__WIN2000__) && defined(ULONG_PTR) typedef ULONG_PTR os_awe_t; #else typedef ulint os_awe_t; diff --git a/innobase/os/os0proc.c b/innobase/os/os0proc.c index 1497ee46b88..614cea63200 100644 --- a/innobase/os/os0proc.c +++ b/innobase/os/os0proc.c @@ -20,13 +20,13 @@ Created 9/30/1995 Heikki Tuuri How to get AWE to compile on Windows? ------------------------------------- -the Visual C++ has to be relatively recent and _WIN32_WINNT has to be -defined to a value >= 0x0500 when windows.h is included. An easy way -to accomplish that is to put +In the project settings of the innobase project the Visual C++ source, +__WIN2000__ has to be defined. -#define _WIN32_WINNT 0x0500 +The Visual C++ has to be relatively recent and _WIN32_WINNT has to be +defined to a value >= 0x0500 when windows.h is included. -to the start of file \mysql\include\config-win.h +#define _WIN32_WINNT 0x0500 Where does AWE work? ------------------- @@ -62,7 +62,7 @@ to a mapped 'physical page' for each 4 kB page in the AWE window */ byte** os_awe_simulate_map; #endif -#ifdef __NT__ +#ifdef __WIN2000__ os_awe_t* os_awe_page_info; ulint os_awe_n_pages; byte* os_awe_window; @@ -84,7 +84,7 @@ os_awe_enable_lock_pages_in_mem(void) return(TRUE); -#elif defined(__NT__) +#elif defined(__WIN2000__) struct { DWORD Count; LUID_AND_ATTRIBUTES Privilege[1]; @@ -187,7 +187,7 @@ os_awe_allocate_physical_mem( return(TRUE); -#elif defined(__NT__) +#elif defined(__WIN2000__) BOOL bResult; os_awe_t NumberOfPages; /* Question: why does Windows use the name ULONG_PTR for @@ -318,7 +318,7 @@ os_awe_allocate_virtual_mem_window( return(os_awe_simulate_window); -#elif defined(__NT__) +#elif defined(__WIN2000__) byte* ptr; if (size > 0x7FFFFFFFFF) { @@ -424,7 +424,7 @@ os_awe_map_physical_mem_to_window( return(TRUE); -#elif defined(__NT__) +#elif defined(__WIN2000__) BOOL bResult; os_awe_t n_pages; diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index e1d436a879c..d855a6aece5 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1008,7 +1008,7 @@ innobase_start_or_create_for_mysql(void) srv_startup_is_before_trx_rollback_phase = TRUE; os_aio_use_native_aio = FALSE; -#if !defined(__NT__) && !defined(UNIV_SIMULATE_AWE) +#if !defined(__WIN2000__) && !defined(UNIV_SIMULATE_AWE) if (srv_use_awe) { fprintf(stderr, diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c index ea11a7b6120..bbb85885886 100644 --- a/libmysql/errmsg.c +++ b/libmysql/errmsg.c @@ -59,7 +59,7 @@ const char *client_errors[]= "No parameters exists in the statement", "Invalid parameter number", "Can't send long data for non string or binary data types (parameter: %d)", - "Using un supported buffer type: %d (parameter: %d)", + "Using unsupported buffer type: %d (parameter: %d)", "Shared memory (%lu)", "Can't open shared memory. Request event don't create (%lu)", "Can't open shared memory. Answer event don't create (%lu)", @@ -114,7 +114,7 @@ const char *client_errors[]= "No parameters exists in the statement", "Invalid parameter number", "Can't send long data for non string or binary data types (parameter: %d)", - "Using un supported buffer type: %d (parameter: %d)", + "Using unsupported buffer type: %d (parameter: %d)", "Shared memory (%lu)", "Can't open shared memory. Request event don't create (%lu)", "Can't open shared memory. Answer event don't create (%lu)", @@ -167,7 +167,7 @@ const char *client_errors[]= "No parameters exists in the statement", "Invalid parameter number", "Can't send long data for non string or binary data types (parameter: %d)", - "Using un supported buffer type: %d (parameter: %d)", + "Using unsupported buffer type: %d (parameter: %d)", "Shared memory (%lu)", "Can't open shared memory. Request event don't create (%lu)", "Can't open shared memory. Answer event don't create (%lu)", diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 08011c376fb..932bc276814 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -3932,19 +3932,40 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length) unsigned int alloc_stmt_fields(MYSQL_STMT *stmt) { - MYSQL_FIELD *fields; + MYSQL_FIELD *fields, *field, *end; + MEM_ROOT *alloc= &stmt->mem_root; if (!stmt->mysql->field_count) return 0; + stmt->field_count= stmt->mysql->field_count; - fields= stmt->mysql->fields; - if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(&stmt->mem_root, - sizeof(fields))) || - !(stmt->bind= (MYSQL_BIND *) alloc_root(&stmt->mem_root, + /* + Get the field information for non-select statements + like SHOW and DESCRIBE commands + */ + if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(alloc, + sizeof(MYSQL_FIELD) * stmt->field_count)) || + !(stmt->bind= (MYSQL_BIND *) alloc_root(alloc, sizeof(MYSQL_BIND ) * stmt->field_count))) return 0; - memcpy((char *)stmt->fields, (char *)fields, sizeof(fields)); + + for (fields= stmt->mysql->fields, end= fields+stmt->field_count, + field= stmt->fields; + field && fields < end; fields++, field++) + { + field->db = strdup_root(alloc,fields->db); + field->table = strdup_root(alloc,fields->table); + field->org_table= strdup_root(alloc,fields->org_table); + field->name = strdup_root(alloc,fields->name); + field->org_name = strdup_root(alloc,fields->org_name); + field->length = fields->length; + field->type = fields->type; + field->flags = fields->flags; + field->decimals = fields->decimals; + field->def = fields->def ? strdup_root(alloc,fields->def): 0; + field->max_length= 0; + } return stmt->field_count; } @@ -4356,6 +4377,7 @@ my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt) static my_bool int_is_null_true= 1; /* Used for MYSQL_TYPE_NULL */ static my_bool int_is_null_false= 0; static my_bool int_is_null_dummy; +static unsigned long param_length_is_dummy; /* Setup the parameter data buffers from application @@ -5041,7 +5063,7 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) param->is_null= &int_is_null_dummy; if (!param->length) - param->length= ¶m->buffer_length; + param->length= ¶m_length_is_dummy; param->param_number= param_count++; /* Setup data copy functions for the different supported types */ @@ -5318,22 +5340,42 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) */ static my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list) { + MYSQL *mysql; my_bool error= 0; DBUG_ENTER("mysql_stmt_close"); DBUG_ASSERT(stmt != 0); + + mysql= stmt->mysql; + if (mysql->status != MYSQL_STATUS_READY) + { + /* Clear the current execution status */ + DBUG_PRINT("warning",("Not all packets read, clearing them")); + for (;;) + { + ulong pkt_len; + if ((pkt_len= net_safe_read(mysql)) == packet_error) + break; + if (pkt_len <= 8 && mysql->net.read_pos[0] == 254) + break; + } + mysql->status= MYSQL_STATUS_READY; + } if (stmt->state == MY_ST_PREPARE || stmt->state == MY_ST_EXECUTE) { char buff[4]; int4store(buff, stmt->stmt_id); - error= simple_command(stmt->mysql, COM_CLOSE_STMT, buff, 4, 1); + error= simple_command(mysql, COM_CLOSE_STMT, buff, 4, 1); + } + if (!error) + { + mysql_free_result(stmt->result); + free_root(&stmt->mem_root, MYF(0)); + if (!skip_list) + mysql->stmts= list_delete(mysql->stmts, &stmt->list); + mysql->status= MYSQL_STATUS_READY; + my_free((gptr) stmt, MYF(MY_WME)); } - mysql_free_result(stmt->result); - free_root(&stmt->mem_root, MYF(0)); - if (!skip_list) - stmt->mysql->stmts= list_delete(stmt->mysql->stmts, &stmt->list); - stmt->mysql->status= MYSQL_STATUS_READY; - my_free((gptr) stmt, MYF(MY_WME)); DBUG_RETURN(error); } diff --git a/mysql-test/r/rpl_user_variables.result b/mysql-test/r/rpl_user_variables.result new file mode 100644 index 00000000000..618efb3840d --- /dev/null +++ b/mysql-test/r/rpl_user_variables.result @@ -0,0 +1,78 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +stop slave; +reset master; +drop table if exists t1; +create table t1(n char(30)); +set @i1:=12345678901234, @i2:=-12345678901234, @i3:=0, @i4:=-1; +set @s1:='This is a test', @r1:=12.5, @r2:=-12.5; +set @n1:=null; +set @s2:='', @s3:='abc\'def', @s4:= 'abc\\def', @s5:= 'abc''def'; +insert into t1 values (@i1), (@i2), (@i3), (@i4); +insert into t1 values (@r1), (@r2); +insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5); +insert into t1 values (@n1); +insert into t1 values (@n2); +insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1); +insert into t1 values (@a+(@b:=@a+1)); +set @q:='abc'; +insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2')); +set @a:=5; +insert into t1 values (@a),(@a); +start slave; +select * from t1; +n +12345678901234 +-12345678901234 +0 +-1 +12.5 +-12.5 +This is a test + +abc'def +abc\def +abc'def +NULL +NULL +0 +1 +2 +5 +abc +abcn1 +abcn1n2 +5 +5 +show binlog events from 141; +Log_name Pos Event_type Server_id Orig_log_pos Info +slave-bin.000001 141 User var 2 141 @i1=12345678901234 +slave-bin.000001 184 User var 2 184 @i2=-12345678901234 +slave-bin.000001 227 User var 2 227 @i3=0 +slave-bin.000001 270 User var 2 270 @i4=-1 +slave-bin.000001 313 Query 1 313 use `test`; insert into t1 values (@i1), (@i2), (@i3), (@i4) +slave-bin.000001 396 User var 2 396 @r1=12.5 +slave-bin.000001 439 User var 2 439 @r2=-12.5 +slave-bin.000001 482 Query 1 482 use `test`; insert into t1 values (@r1), (@r2) +slave-bin.000001 551 User var 2 551 @s1='This is a test' +slave-bin.000001 601 User var 2 601 @s2='' +slave-bin.000001 637 User var 2 637 @s3='abc'def' +slave-bin.000001 680 User var 2 680 @s4='abc\def' +slave-bin.000001 723 User var 2 723 @s5='abc'def' +slave-bin.000001 766 Query 1 766 use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5) +slave-bin.000001 856 User var 2 856 @n1=NULL +slave-bin.000001 882 Query 1 882 use `test`; insert into t1 values (@n1) +slave-bin.000001 944 Query 1 944 use `test`; insert into t1 values (@n2) +slave-bin.000001 1006 Query 1 1006 use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1) +slave-bin.000001 1094 User var 2 1094 @a='2' +slave-bin.000001 1130 Query 1 1130 use `test`; insert into t1 values (@a+(@b:=@a+1)) +slave-bin.000001 1202 User var 2 1202 @q='abc' +slave-bin.000001 1240 Query 1 1240 use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2')) +slave-bin.000001 1344 User var 2 1344 @a=5 +slave-bin.000001 1386 Query 1 1386 use `test`; insert into t1 values (@a),(@a) +drop table t1; +stop slave; diff --git a/mysql-test/t/rpl_user_variables.test b/mysql-test/t/rpl_user_variables.test new file mode 100644 index 00000000000..7de52367fba --- /dev/null +++ b/mysql-test/t/rpl_user_variables.test @@ -0,0 +1,39 @@ +source include/master-slave.inc; +connection master; +save_master_pos; +connection slave; +sync_with_master; +stop slave; +reset master; +connection master; +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1(n char(30)); +set @i1:=12345678901234, @i2:=-12345678901234, @i3:=0, @i4:=-1; +set @s1:='This is a test', @r1:=12.5, @r2:=-12.5; +set @n1:=null; +set @s2:='', @s3:='abc\'def', @s4:= 'abc\\def', @s5:= 'abc''def'; +insert into t1 values (@i1), (@i2), (@i3), (@i4); +insert into t1 values (@r1), (@r2); +insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5); +insert into t1 values (@n1); +insert into t1 values (@n2); +insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1); +insert into t1 values (@a+(@b:=@a+1)); +set @q:='abc'; +insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2')); +set @a:=5; +insert into t1 values (@a),(@a); +save_master_pos; +connection slave; +start slave; +sync_with_master; +select * from t1; +show binlog events from 141; +connection master; +drop table t1; +save_master_pos; +connection slave; +sync_with_master; +stop slave; diff --git a/mysys/charset.c b/mysys/charset.c index 68377aec355..a192eab8eb6 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -59,6 +59,7 @@ static void simple_cs_init_functions(CHARSET_INFO *cs) cs->strnxfrm = my_strnxfrm_simple; cs->strnncoll = my_strnncoll_simple; + cs->strnncollsp = my_strnncollsp_simple; cs->like_range = my_like_range_simple; cs->wildcmp = my_wildcmp_8bit; cs->mb_wc = my_mb_wc_8bit; @@ -83,6 +84,8 @@ static void simple_cs_init_functions(CHARSET_INFO *cs) cs->strntod = my_strntod_8bit; cs->scan = my_scan_8bit; cs->mbmaxlen = 1; + cs->numchars = my_numchars_8bit; + cs->charpos = my_charpos_8bit; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 8c5a0ec0868..19e0bb5f9ed 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1280,11 +1280,11 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, } else thd=current_thd; // In WHERE / const clause - udf_func *tmp_udf=find_udf(u_d->name,(uint) strlen(u_d->name),1); + udf_func *tmp_udf=find_udf(u_d->name.str,(uint) u_d->name.length,1); if (!tmp_udf) { - my_printf_error(ER_CANT_FIND_UDF,ER(ER_CANT_FIND_UDF),MYF(0),u_d->name, + my_printf_error(ER_CANT_FIND_UDF,ER(ER_CANT_FIND_UDF),MYF(0),u_d->name.str, errno); DBUG_RETURN(1); } @@ -1930,6 +1930,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, entry->value=0; entry->length=0; entry->update_query_id=0; + entry->used_query_id=current_thd->query_id; entry->type=STRING_RESULT; memcpy(entry->name.str, name.str, name.length+1); if (hash_insert(hash,(byte*) entry)) @@ -2063,7 +2064,7 @@ Item_func_set_user_var::val_str(String *str) { String *res=args[0]->val_str(str); if (!res) // Null value - update_hash((void*) 0,0,STRING_RESULT, default_charset_info); + update_hash((void*) 0, 0, STRING_RESULT, default_charset_info); else update_hash(res->c_ptr(),res->length()+1,STRING_RESULT,res->charset()); return res; @@ -2162,14 +2163,58 @@ longlong Item_func_get_user_var::val_int() return LL(0); // Impossible } +/* From sql_parse.cc */ +extern bool is_update_query(enum enum_sql_command command); void Item_func_get_user_var::fix_length_and_dec() { + BINLOG_USER_VAR_EVENT *user_var_event; THD *thd=current_thd; maybe_null=1; decimals=NOT_FIXED_DEC; max_length=MAX_BLOB_WIDTH; - var_entry= get_variable(&thd->user_vars, name, 0); + + if ((var_entry= get_variable(&thd->user_vars, name, 0))) + { + if (opt_bin_log && is_update_query(thd->lex.sql_command) && + var_entry->used_query_id != thd->query_id) + { + /* + First we need to store value of var_entry, when the next situation appers: + > set @a:=1; + > insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1); + We have to write to binlog value @a= 1; + */ + uint size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length; + if (!(user_var_event= (BINLOG_USER_VAR_EVENT *) thd->alloc(size))) + goto err; + + user_var_event->value= (char*) user_var_event + + ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)); + user_var_event->user_var_event= var_entry; + user_var_event->type= var_entry->type; + user_var_event->charset_number= var_entry->var_charset->number; + if (!var_entry->value) + { + /* NULL value*/ + user_var_event->length= 0; + user_var_event->value= 0; + } + else + { + user_var_event->length= var_entry->length; + memcpy(user_var_event->value, var_entry->value, + var_entry->length); + } + var_entry->used_query_id= thd->query_id; + if (insert_dynamic(&thd->user_var_events, (gptr) &user_var_event)) + goto err; + } + } + return; +err: + thd->fatal_error= 1; + return; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 21d28048848..73f2968c5f6 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -805,13 +805,8 @@ String *Item_func_insert::val_str(String *str) if (args[0]->null_value || args[1]->null_value || args[2]->null_value || args[3]->null_value) goto null; /* purecov: inspected */ -#ifdef USE_MB - if (use_mb(res->charset()) && !args[0]->binary()) - { - start=res->charpos(start); - length=res->charpos(length,start); - } -#endif + start=res->charpos(start); + length=res->charpos(length,start); if (start > res->length()+1) return res; // Wrong param; skip insert if (length > res->length()-start) @@ -878,10 +873,7 @@ String *Item_func_left::val_str(String *str) return 0; if (length <= 0) return &empty_string; -#ifdef USE_MB - if (use_mb(res->charset()) && !binary()) - length = res->charpos(length); -#endif + length= res->charpos(length); if (res->length() > (ulong) length) { // Safe even if const arg if (!res->alloced_length()) @@ -927,19 +919,11 @@ String *Item_func_right::val_str(String *str) return &empty_string; /* purecov: inspected */ if (res->length() <= (uint) length) return res; /* purecov: inspected */ -#ifdef USE_MB - if (use_mb(res->charset()) && !binary()) - { - uint start=res->numchars()-(uint) length; - if (start<=0) return res; - start=res->charpos(start); - tmp_value.set(*res,start,res->length()-start); - } - else -#endif - { - tmp_value.set(*res,(res->length()- (uint) length),(uint) length); - } + + uint start=res->numchars()-(uint) length; + if (start<=0) return res; + start=res->charpos(start); + tmp_value.set(*res,start,res->length()-start); return &tmp_value; } @@ -960,13 +944,8 @@ String *Item_func_substr::val_str(String *str) if ((null_value=(args[0]->null_value || args[1]->null_value || (arg_count == 3 && args[2]->null_value)))) return 0; /* purecov: inspected */ -#ifdef USE_MB - if (use_mb(res->charset()) && !binary()) - { - start=res->charpos(start); - length=res->charpos(length,start); - } -#endif + start=res->charpos(start); + length=res->charpos(length,start); if (start < 0 || (uint) start+1 > res->length() || length <= 0) return &empty_string; diff --git a/sql/log.cc b/sql/log.cc index 0c06ae551aa..9a523915673 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1104,6 +1104,23 @@ bool MYSQL_LOG::write(Log_event* event_info) if (e.write(file)) goto err; } + if (thd->user_var_events.elements) + { + for (uint i= 0; i < thd->user_var_events.elements; i++) + { + BINLOG_USER_VAR_EVENT *user_var_event; + get_dynamic(&thd->user_var_events,(gptr) &user_var_event, i); + User_var_log_event e(thd, user_var_event->user_var_event->name.str, + user_var_event->user_var_event->name.length, + user_var_event->value, + user_var_event->length, + user_var_event->type, + user_var_event->charset_number); + e.set_log_pos(this); + if (e.write(file)) + goto err; + } + } if (thd->variables.convert_set) { char buf[256], *p; diff --git a/sql/log_event.cc b/sql/log_event.cc index b7d0470a4d8..34e3deebf69 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -227,6 +227,7 @@ const char* Log_event::get_type_str() case DELETE_FILE_EVENT: return "Delete_file"; case EXEC_LOAD_EVENT: return "Exec_load"; case RAND_EVENT: return "RAND"; + case USER_VAR_EVENT: return "User var"; default: /* impossible */ return "Unknown"; } } @@ -614,6 +615,9 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, case RAND_EVENT: ev = new Rand_log_event(buf, old_format); break; + case USER_VAR_EVENT: + ev = new User_var_log_event(buf, old_format); + break; default: break; } @@ -1979,8 +1983,246 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli) rli->inc_pending(get_event_len()); return 0; } +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + User_var_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + User_var_log_event::pack_info() + + ****************************************************************************/ +#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) +void User_var_log_event::pack_info(Protocol* protocol) +{ + char *buf= 0; + uint val_offset= 2 + name_len; + uint event_len= val_offset; + + if (is_null) + { + buf= my_malloc(val_offset + 5, MYF(MY_WME)); + strmov(buf + val_offset, "NULL"); + event_len= val_offset + 4; + } + else + { + switch (type) { + case REAL_RESULT: + double real_val; + float8get(real_val, val); + buf= my_malloc(val_offset + FLOATING_POINT_BUFFER, MYF(MY_WME)); + event_len += my_sprintf(buf + val_offset, + (buf + val_offset, "%.14g", real_val)); + break; + case INT_RESULT: + buf= my_malloc(val_offset + 22, MYF(MY_WME)); + event_len= longlong10_to_str(uint8korr(val), buf + val_offset,-10)-buf; + break; + case STRING_RESULT: + /* + This is correct as pack_info is used for SHOW BINLOG command + only. But be carefull this is may be incorrect in other cases as + string may contain \ and '. + */ + buf= my_malloc(val_offset + 2 + val_len, MYF(MY_WME)); + buf[val_offset]= '\''; + memcpy(buf + val_offset + 1, val, val_len); + buf[val_offset + val_len]= '\''; + event_len= val_offset + 1 + val_len; + break; + case ROW_RESULT: + DBUG_ASSERT(1); + return; + } + } + buf[0]= '@'; + buf[1+name_len]= '='; + memcpy(buf+1, name, name_len); + protocol->store(buf, event_len); + my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); +} +#endif // !MYSQL_CLIENT +/***************************************************************************** + + User_var_log_event::User_var_log_event() + + ****************************************************************************/ +User_var_log_event::User_var_log_event(const char* buf, bool old_format) + :Log_event(buf, old_format) +{ + buf+= (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; + name_len= uint4korr(buf); + name= (char *) buf + UV_NAME_LEN_SIZE; + is_null= buf[UV_NAME_LEN_SIZE + name_len]; + if (is_null) + { + type= STRING_RESULT; + val_len= 0; + val= 0; + } + else + { + type= (Item_result) buf[UV_VAL_IS_NULL + UV_NAME_LEN_SIZE + name_len]; + charset_number= uint4korr(buf + UV_NAME_LEN_SIZE + name_len + + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE); + val_len= uint4korr(buf + UV_NAME_LEN_SIZE + name_len + + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + + UV_CHARSET_NUMBER_SIZE); + val= (char *) buf + UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL + + UV_VAL_TYPE_SIZE + UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE; + } +} + +/***************************************************************************** + + User_var_log_event::write_data() + + ****************************************************************************/ +int User_var_log_event::write_data(IO_CACHE* file) +{ + char buf[UV_NAME_LEN_SIZE]; + char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + + UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE]; + char buf2[8]; + char *pos= buf2; + int4store(buf, name_len); + buf1[0]= is_null; + if (!is_null) + { + buf1[1]= type; + int4store(buf1 + 2, charset_number); + int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len); + + switch (type) { + case REAL_RESULT: + float8store(buf2, *(double*) val); + break; + case INT_RESULT: + int8store(buf2, *(longlong*) val); + break; + case STRING_RESULT: + pos= val; + break; + case ROW_RESULT: + DBUG_ASSERT(1); + return 0; + } + return (my_b_safe_write(file, (byte*) buf, sizeof(buf)) || + my_b_safe_write(file, (byte*) name, name_len) || + my_b_safe_write(file, (byte*) buf1, sizeof(buf1)) || + my_b_safe_write(file, (byte*) pos, val_len)); + } + + return (my_b_safe_write(file, (byte*) buf, sizeof(buf)) || + my_b_safe_write(file, (byte*) name, name_len) || + my_b_safe_write(file, (byte*) buf1, 1)); +} + +/***************************************************************************** + + User_var_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void User_var_log_event::print(FILE* file, bool short_form, char* last_db) +{ + if (!short_form) + { + print_header(file); + fprintf(file, "\tUser_var\n"); + } + + fprintf(file, "SET @"); + my_fwrite(file, (byte*) name, (uint) (name_len), MYF(MY_NABP | MY_WME)); + + if (is_null) + { + fprintf(file, ":=NULL;\n"); + } + else + { + switch (type) { + case REAL_RESULT: + double real_val; + float8get(real_val, val); + fprintf(file, ":=%.14g;\n", real_val); + break; + case INT_RESULT: + char int_buf[22]; + longlong10_to_str(uint8korr(val), int_buf, -10); + fprintf(file, ":=%s;\n", int_buf); + break; + case STRING_RESULT: + fprintf(file, ":='%s';\n", val); + break; + case ROW_RESULT: + DBUG_ASSERT(1); + return; + } + } + fflush(file); +} #endif +/***************************************************************************** + + User_var_log_event::exec_event() + + ****************************************************************************/ +#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) +int User_var_log_event::exec_event(struct st_relay_log_info* rli) +{ + Item *it= 0; + CHARSET_INFO *charset= log_cs; + LEX_STRING user_var_name; + user_var_name.str= name; + user_var_name.length= name_len; + + if (type != ROW_RESULT) + init_sql_alloc(&thd->mem_root, 8192,0); + + if (is_null) + { + it= new Item_null(); + } + else + { + switch (type) { + case REAL_RESULT: + double real_val; + float8get(real_val, val); + it= new Item_real(real_val); + break; + case INT_RESULT: + it= new Item_int((longlong) uint8korr(val)); + break; + case STRING_RESULT: + it= new Item_string(val, val_len, charset); + break; + case ROW_RESULT: + DBUG_ASSERT(1); + return 0; + } + charset= get_charset(charset_number, MYF(0)); + } + Item_func_set_user_var e(user_var_name, it); + e.fix_fields(thd, 0, 0); + e.update_hash(val, val_len, type, charset); + free_root(&thd->mem_root,0); + + rli->inc_pending(get_event_len()); + return 0; +} +#endif // !MYSQL_CLIENT + /***************************************************************************** ***************************************************************************** diff --git a/sql/log_event.h b/sql/log_event.h index 29fdf80b03b..567bf279ff1 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -173,6 +173,14 @@ struct sql_ex_info #define RAND_SEED1_OFFSET 0 #define RAND_SEED2_OFFSET 8 +/* User_var event post-header */ + +#define UV_VAL_LEN_SIZE 4 +#define UV_VAL_IS_NULL 1 +#define UV_VAL_TYPE_SIZE 1 +#define UV_NAME_LEN_SIZE 4 +#define UV_CHARSET_NUMBER_SIZE 4 + /* Load event post-header */ #define L_THREAD_ID_OFFSET 0 @@ -222,7 +230,7 @@ enum Log_event_type START_EVENT = 1, QUERY_EVENT =2, STOP_EVENT=3, ROTATE_EVENT = 4, INTVAR_EVENT=5, LOAD_EVENT=6, SLAVE_EVENT=7, CREATE_FILE_EVENT=8, APPEND_BLOCK_EVENT=9, EXEC_LOAD_EVENT=10, DELETE_FILE_EVENT=11, - NEW_LOAD_EVENT=12, RAND_EVENT=13 + NEW_LOAD_EVENT=12, RAND_EVENT=13, USER_VAR_EVENT=14 }; enum Int_event_type @@ -613,6 +621,46 @@ class Rand_log_event: public Log_event bool is_valid() { return 1; } }; +/***************************************************************************** + + User var Log Event class + + ****************************************************************************/ +class User_var_log_event: public Log_event +{ +public: + char *name; + uint name_len; + char *val; + ulong val_len; + Item_result type; + uint charset_number; + byte is_null; +#ifndef MYSQL_CLIENT + User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg, + char *val_arg, ulong val_len_arg, Item_result type_arg, + uint charset_number_arg) + :Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg), + val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg) + { is_null= !val; } + void pack_info(Protocol* protocol); + int exec_event(struct st_relay_log_info* rli); +#else + void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif + + User_var_log_event(const char* buf, bool old_format); + ~User_var_log_event() {} + Log_event_type get_type_code() { return USER_VAR_EVENT;} + int get_data_size() + { + return (is_null ? UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL : + UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + + UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE + val_len); + } + int write_data(IO_CACHE* file); + bool is_valid() { return 1; } +}; /***************************************************************************** diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f70bd304618..3975f65a43c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -146,6 +146,17 @@ THD::THD():user_time(0), is_fatal_error(0), (hash_get_key) get_var_key, (hash_free_key) free_user_var,0); + /* For user vars replication*/ + if (opt_bin_log) + my_init_dynamic_array(&user_var_events, + sizeof(BINLOG_USER_VAR_EVENT *), + 16, + 16); + else + bzero((char*) &user_var_events, sizeof(user_var_events)); + + + /* Prepared statements */ last_prepared_stmt= 0; init_tree(&prepared_statements, 0, 0, sizeof(PREP_STMT), @@ -244,6 +255,7 @@ void THD::cleanup(void) close_thread_tables(this); } close_temporary_tables(this); + delete_dynamic(&user_var_events); hash_free(&user_vars); if (global_read_lock) unlock_global_read_lock(this); diff --git a/sql/sql_class.h b/sql/sql_class.h index 5dd8c4a13ad..32ad4a8fbd3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -57,6 +57,15 @@ typedef struct st_log_info ~st_log_info() { pthread_mutex_destroy(&lock);} } LOG_INFO; +typedef struct st_user_var_events +{ + user_var_entry *user_var_event; + char *value; + ulong length; + Item_result type; + uint charset_number; +} BINLOG_USER_VAR_EVENT; + class Log_event; class MYSQL_LOG { @@ -523,6 +532,8 @@ public: uint select_number; //number of select (used for EXPLAIN) /* variables.transaction_isolation is reset to this after each commit */ enum_tx_isolation session_tx_isolation; + /* for user variables replication*/ + DYNAMIC_ARRAY user_var_events; // extend scramble to handle new auth char scramble[SCRAMBLE41_LENGTH+1]; // old scramble is needed to handle old clients @@ -917,7 +928,7 @@ class user_var_entry public: LEX_STRING name; char *value; - ulong length, update_query_id; + ulong length, update_query_id, used_query_id; Item_result type; CHARSET_INFO *var_charset; }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4f248348d32..cdc5c6da1a6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -396,6 +396,10 @@ void init_update_queries(void) uc_update_queries[SQLCOM_UPDATE_MULTI]=1; } +bool is_update_query(enum enum_sql_command command) +{ + return uc_update_queries[command]; +} /* Check if maximum queries per hour limit has been reached @@ -1225,6 +1229,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } thd->query_length= length; thd->query= packet; + thd->net.last_error[0]= '\0'; VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query_id= query_id++; VOID(pthread_mutex_unlock(&LOCK_thread_count)); @@ -2709,7 +2714,7 @@ mysql_execute_command(THD *thd) if (check_access(thd,DELETE_ACL,"mysql",0,1)) break; #ifdef HAVE_DLOPEN - if (!(res = mysql_drop_function(thd,lex->udf.name))) + if (!(res = mysql_drop_function(thd,&lex->udf.name))) send_ok(thd); #else res= -1; @@ -3157,6 +3162,9 @@ mysql_init_query(THD *thd) thd->sent_row_count= thd->examined_row_count= 0; thd->is_fatal_error= thd->rand_used= 0; thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS; + if (opt_bin_log) + reset_dynamic(&thd->user_var_events); + DBUG_VOID_RETURN; } diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 8c12261f949..21e38397842 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -363,46 +363,13 @@ bool String::append(IO_CACHE* file, uint32 arg_length) uint32 String::numchars() { -#ifdef USE_MB - register uint32 n=0,mblen; - register const char *mbstr=Ptr; - register const char *end=mbstr+str_length; - if (use_mb(str_charset)) - { - while (mbstr < end) { - if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen; - else ++mbstr; - ++n; - } - return n; - } - else -#endif - return str_length; + return str_charset->numchars(str_charset, Ptr, Ptr+str_length); } int String::charpos(int i,uint32 offset) { -#ifdef USE_MB - register uint32 mblen; - register const char *mbstr=Ptr+offset; - register const char *end=Ptr+str_length; - if (use_mb(str_charset)) - { - if (i<=0) return i; - while (i && mbstr < end) { - if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen; - else ++mbstr; - --i; - } - if ( INT_MAX32-i <= (int) (mbstr-Ptr-offset)) - return INT_MAX32; - else - return (int) ((mbstr-Ptr-offset)+i); - } - else -#endif - return i; + if (i<0) return i; + return str_charset->charpos(str_charset,Ptr+offset,Ptr+str_length,i); } int String::strstr(const String &s,uint32 offset) @@ -573,66 +540,10 @@ void String::qs_append(const char &c) int sortcmp(const String *x,const String *y) { - const char *s= x->ptr(); - const char *t= y->ptr(); - uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len); - - if (use_strnxfrm(x->str_charset)) - { -#ifndef CMP_ENDSPACE - while (x_len && my_isspace(x->str_charset,s[x_len-1])) - x_len--; - while (y_len && my_isspace(x->str_charset,t[y_len-1])) - y_len--; -#endif - return my_strnncoll(x->str_charset, - (unsigned char *)s,x_len,(unsigned char *)t,y_len); - } - else - { - x_len-=len; // For easy end space test - y_len-=len; - if (x->str_charset->sort_order) - { - 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 */ - { - if (y_len) - { - const char *end=t+y_len; - for (; t != end ; t++) - if (!my_isspace(x->str_charset,*t)) - return -1; - } - else - { - const char *end=s+x_len; - for (; s != end ; s++) - if (!my_isspace(x->str_charset,*s)) - return 1; - } - return 0; - } -#else - return (int) (x_len-y_len); -#endif /* CMP_ENDSPACE */ - } + CHARSET_INFO *cs= x->str_charset; + return cs->strnncollsp(cs, + (unsigned char *) x->ptr(),x->length(), + (unsigned char *) y->ptr(),y->length()); } diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 324befcb59e..3b362bf3e3f 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -74,7 +74,7 @@ static HASH udf_hash; static rw_lock_t THR_LOCK_udf; -static udf_func *add_udf(char *name, Item_result ret, char *dl, +static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl, Item_udftype typ); static void del_udf(udf_func *udf); static void *find_udf_dl(const char *dl); @@ -84,8 +84,8 @@ static void init_syms(udf_func *tmp) { char nm[MAX_FIELD_NAME+16],*end; - tmp->func = dlsym(tmp->dlhandle, tmp->name); - end=strmov(nm,tmp->name); + tmp->func = dlsym(tmp->dlhandle, tmp->name.str); + end=strmov(nm,tmp->name.str); (void) strmov(end,"_init"); tmp->func_init = dlsym(tmp->dlhandle, nm); (void) strmov(end,"_deinit"); @@ -103,8 +103,8 @@ extern "C" byte* get_hash_key(const byte *buff,uint *length, my_bool not_used __attribute__((unused))) { udf_func *udf=(udf_func*) buff; - *length=(uint) udf->name_length; - return (byte*) udf->name; + *length=(uint) udf->name.length; + return (byte*) udf->name.str; } /* @@ -161,14 +161,16 @@ void udf_init() while (!(error = read_record_info.read_record(&read_record_info))) { DBUG_PRINT("info",("init udf record")); - char *name=get_field(&mem, table, 0); + LEX_STRING name; + name.str=get_field(&mem, table, 0); + name.length = strlen(name.str); char *dl_name= get_field(&mem, table, 2); bool new_dl=0; Item_udftype udftype=UDFTYPE_FUNCTION; if (table->fields >= 4) // New func table udftype=(Item_udftype) table->field[3]->val_int(); - if (!(tmp = add_udf(name,(Item_result) table->field[1]->val_int(), + if (!(tmp = add_udf(&name,(Item_result) table->field[1]->val_int(), dl_name, udftype))) { sql_print_error("Can't alloc memory for udf function: name"); @@ -250,10 +252,10 @@ static void del_udf(udf_func *udf) The functions will be automaticly removed when the least threads doesn't use it anymore */ - char *name= udf->name; - uint name_length=udf->name_length; - udf->name=(char*) "*"; - udf->name_length=1; + char *name= udf->name.str; + uint name_length=udf->name.length; + udf->name.str=(char*) "*"; + udf->name.length=1; hash_update(&udf_hash,(byte*) udf,(byte*) name,name_length); } DBUG_VOID_RETURN; @@ -322,7 +324,7 @@ static void *find_udf_dl(const char *dl) /* Assume that name && dl is already allocated */ -static udf_func *add_udf(char *name, Item_result ret, char *dl, +static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl, Item_udftype type) { if (!name || !dl || !(uint) type || (uint) type > (uint) UDFTYPE_AGGREGATE) @@ -331,8 +333,7 @@ static udf_func *add_udf(char *name, Item_result ret, char *dl, if (!tmp) return 0; bzero((char*) tmp,sizeof(*tmp)); - tmp->name = name; - tmp->name_length=(uint) strlen(tmp->name); + tmp->name = *name; //dup !! tmp->dl = dl; tmp->returns = ret; tmp->type = type; @@ -370,14 +371,14 @@ int mysql_create_function(THD *thd,udf_func *udf) send_error(thd, ER_UDF_NO_PATHS,ER(ER_UDF_NO_PATHS)); DBUG_RETURN(1); } - if (udf->name_length > NAME_LEN) + if (udf->name.length > NAME_LEN) { net_printf(thd, ER_TOO_LONG_IDENT,udf->name); DBUG_RETURN(1); } rw_wrlock(&THR_LOCK_udf); - if ((hash_search(&udf_hash,(byte*) udf->name, udf->name_length))) + if ((hash_search(&udf_hash,(byte*) udf->name.str, udf->name.length))) { net_printf(thd, ER_UDF_EXISTS, udf->name); goto err; @@ -401,9 +402,9 @@ int mysql_create_function(THD *thd,udf_func *udf) net_printf(thd, ER_CANT_FIND_DL_ENTRY, udf->name); goto err; } - udf->name=strdup_root(&mem,udf->name); + udf->name.str=strdup_root(&mem,udf->name.str); udf->dl=strdup_root(&mem,udf->dl); - if (!(u_d=add_udf(udf->name,udf->returns,udf->dl,udf->type))) + if (!(u_d=add_udf(&udf->name,udf->returns,udf->dl,udf->type))) { send_error(thd,0); // End of memory goto err; @@ -425,7 +426,7 @@ int mysql_create_function(THD *thd,udf_func *udf) goto err; restore_record(table,2); // Get default values for fields - table->field[0]->store(u_d->name, u_d->name_length, default_charset_info); + table->field[0]->store(u_d->name.str, u_d->name.length, default_charset_info); table->field[1]->store((longlong) u_d->returns); table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), default_charset_info); if (table->fields >= 4) // If not old func format @@ -450,7 +451,7 @@ int mysql_create_function(THD *thd,udf_func *udf) } -int mysql_drop_function(THD *thd,const char *udf_name) +int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) { TABLE *table; TABLE_LIST tables; @@ -462,8 +463,8 @@ int mysql_drop_function(THD *thd,const char *udf_name) DBUG_RETURN(1); } rw_wrlock(&THR_LOCK_udf); - if (!(udf=(udf_func*) hash_search(&udf_hash,(byte*) udf_name, - (uint) strlen(udf_name)))) + if (!(udf=(udf_func*) hash_search(&udf_hash,(byte*) udf_name->str, + (uint) udf_name->length))) { net_printf(thd, ER_FUNCTION_NOT_DEFINED, udf_name); goto err; @@ -481,8 +482,8 @@ int mysql_drop_function(THD *thd,const char *udf_name) tables.real_name= tables.alias= (char*) "func"; if (!(table = open_ltable(thd,&tables,TL_WRITE))) goto err; - if (!table->file->index_read_idx(table->record[0],0,(byte*) udf_name, - (uint) strlen(udf_name), + if (!table->file->index_read_idx(table->record[0],0,(byte*) udf_name->str, + (uint) udf_name->length, HA_READ_KEY_EXACT)) { int error; diff --git a/sql/sql_udf.h b/sql/sql_udf.h index 1ee9c44ce48..29a351ac52f 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -25,8 +25,7 @@ enum Item_udftype {UDFTYPE_FUNCTION=1,UDFTYPE_AGGREGATE}; typedef struct st_udf_func { - char *name; - int name_length; + LEX_STRING name; Item_result returns; Item_udftype type; char *dl; @@ -61,7 +60,7 @@ class udf_handler :public Sql_alloc initialized(0) {} ~udf_handler(); - const char *name() const { return u_d ? u_d->name : "?"; } + const char *name() const { return u_d ? u_d->name.str : "?"; } Item_result result_type () const { return u_d ? u_d->returns : STRING_RESULT;} bool get_arguments(); @@ -140,5 +139,5 @@ void udf_init(void),udf_free(void); udf_func *find_udf(const char *name, uint len=0,bool mark_used=0); void free_udf(udf_func *udf); int mysql_create_function(THD *thd,udf_func *udf); -int mysql_drop_function(THD *thd,const char *name); +int mysql_drop_function(THD *thd,const LEX_STRING *name); #endif diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 5ce68245fc8..6e4f519147e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -870,12 +870,11 @@ create: lex->name=$4.str; lex->create_info.options=$3; } - | CREATE udf_func_type UDF_SYM ident + | CREATE udf_func_type UDF_SYM IDENT { LEX *lex=Lex; lex->sql_command = SQLCOM_CREATE_FUNCTION; - lex->udf.name=$4.str; - lex->udf.name_length=$4.length; + lex->udf.name = $4; lex->udf.type= $2; } UDF_RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING @@ -3016,11 +3015,11 @@ drop: lex->drop_if_exists=$3; lex->name=$4.str; } - | DROP UDF_SYM ident + | DROP UDF_SYM IDENT { LEX *lex=Lex; lex->sql_command = SQLCOM_DROP_FUNCTION; - lex->udf.name=$3.str; + lex->udf.name = $3; }; diff --git a/sql/unireg.h b/sql/unireg.h index 724ff3f6197..2dc84720b2d 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -136,6 +136,8 @@ bfill((A)->null_flags,(A)->null_bytes,255);\ #define BIN_LOG_HEADER_SIZE 4 +#define FLOATING_POINT_BUFFER 331 + /* Include prototypes for unireg */ #include "mysqld_error.h" diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index e1cc0b6e8ab..7827b8714ec 100644 --- a/strings/ctype-big5.c +++ b/strings/ctype-big5.c @@ -242,6 +242,16 @@ static int my_strnncoll_big5(CHARSET_INFO *cs __attribute__((unused)), return (int) (len1-len2); } +static +int my_strnncollsp_big5(CHARSET_INFO * cs, + const uchar *s, uint slen, + const uchar *t, uint tlen) +{ + for ( ; slen && my_isspace(cs, s[slen-1]) ; slen--); + for ( ; tlen && my_isspace(cs, t[tlen-1]) ; tlen--); + return my_strnncoll_big5(cs,s,slen,t,tlen); +} + static int my_strnxfrm_big5(CHARSET_INFO *cs __attribute__((unused)), uchar * dest, uint len, const uchar * src, uint srclen) @@ -6236,6 +6246,7 @@ CHARSET_INFO my_charset_big5 = NULL, /* tab_from_uni */ 1, /* strxfrm_multiply */ my_strnncoll_big5, + my_strnncollsp_big5, my_strnxfrm_big5, my_like_range_big5, my_wildcmp_mb, @@ -6243,6 +6254,8 @@ CHARSET_INFO my_charset_big5 = ismbchar_big5, ismbhead_big5, mbcharlen_big5, + my_numchars_mb, + my_charpos_mb, my_mb_wc_big5, /* mb_wc */ my_wc_mb_big5, /* wc_mb */ my_caseup_str_mb, diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 5f9dc9929ab..4d428828826 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -284,6 +284,7 @@ CHARSET_INFO my_charset_bin = NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_binary, /* strnncoll */ + my_strnncoll_binary, my_strnxfrm_bin, /* strxnfrm */ my_like_range_simple, /* like_range */ my_wildcmp_bin, /* wildcmp */ @@ -291,6 +292,8 @@ CHARSET_INFO my_charset_bin = NULL, /* ismbchar */ NULL, /* ismbhead */ NULL, /* mbcharlen */ + my_numchars_8bit, + my_charpos_8bit, my_mb_wc_bin, /* mb_wc */ my_wc_mb_bin, /* wc_mb */ my_caseup_str_bin, /* caseup_str */ diff --git a/strings/ctype-czech.c b/strings/ctype-czech.c index 3e351732212..f42ab66fed9 100644 --- a/strings/ctype-czech.c +++ b/strings/ctype-czech.c @@ -593,6 +593,18 @@ static MY_UNI_IDX idx_uni_8859_2[]={ {0,0,NULL} }; + +static +int my_strnncollsp_czech(CHARSET_INFO * cs, + const uchar *s, uint slen, + const uchar *t, uint tlen) +{ + for ( ; slen && my_isspace(cs, s[slen-1]) ; slen--); + for ( ; tlen && my_isspace(cs, t[tlen-1]) ; tlen--); + return my_strnncoll_czech(cs,s,slen,t,tlen); +} + + CHARSET_INFO my_charset_czech = { 2, /* number */ @@ -608,6 +620,7 @@ CHARSET_INFO my_charset_czech = idx_uni_8859_2, /* tab_from_uni */ 4, /* strxfrm_multiply */ my_strnncoll_czech, + my_strnncollsp_czech, my_strnxfrm_czech, my_like_range_czech, my_wildcmp_8bit, @@ -615,6 +628,8 @@ CHARSET_INFO my_charset_czech = NULL, /* ismbchar */ NULL, /* ismbhead */ NULL, /* mbcharlen */ + my_numchars_8bit, + my_charpos_8bit, my_mb_wc_8bit, /* mb_wc */ my_wc_mb_8bit, /* wc_mb */ my_caseup_str_8bit, diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index 7a2fe48f4ab..e49bf6a38fd 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -8654,6 +8654,7 @@ CHARSET_INFO my_charset_euc_kr = NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple, my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_mb, /* wildcmp */ @@ -8661,6 +8662,8 @@ CHARSET_INFO my_charset_euc_kr = ismbchar_euc_kr, ismbhead_euc_kr, mbcharlen_euc_kr, + my_numchars_mb, + my_charpos_mb, my_mb_wc_euc_kr, /* mb_wc */ my_wc_mb_euc_kr, /* wc_mb */ my_caseup_str_mb, diff --git a/strings/ctype-extra.c b/strings/ctype-extra.c index b7a7bea7bb1..3e3cd38c063 100644 --- a/strings/ctype-extra.c +++ b/strings/ctype-extra.c @@ -2820,6 +2820,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_8859_1, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -2827,6 +2828,8 @@ CHARSET_INFO compiled_charsets[] = { NULL, /* ismbchar */ NULL, /* ismbhead */ NULL, /* mbcharlen */ + my_numchars_8bit, + my_charpos_8bit, my_mb_wc_8bit, /* mb_wc */ my_wc_mb_8bit, /* wc_mb */ my_caseup_str_8bit, @@ -2868,6 +2871,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_cp1251, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -2875,6 +2879,8 @@ CHARSET_INFO compiled_charsets[] = { NULL, /* ismbchar */ NULL, /* ismbhead */ NULL, /* mbcharlen */ + my_numchars_8bit, + my_charpos_8bit, my_mb_wc_8bit, /* mb_wc */ my_wc_mb_8bit, /* wc_mb */ my_caseup_str_8bit, @@ -2915,6 +2921,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_cp1257, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -2922,6 +2929,8 @@ CHARSET_INFO compiled_charsets[] = { NULL, /* ismbchar */ NULL, /* ismbhead */ NULL, /* mbcharlen */ + my_numchars_8bit, + my_charpos_8bit, my_mb_wc_8bit, /* mb_wc */ my_wc_mb_8bit, /* wc_mb */ my_caseup_str_8bit, @@ -2962,6 +2971,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_8859_2, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3010,6 +3020,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_8859_1, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3057,6 +3068,7 @@ CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3104,6 +3116,7 @@ CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3151,6 +3164,7 @@ CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3199,6 +3213,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_8859_1, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3246,6 +3261,7 @@ CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3293,6 +3309,7 @@ CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3340,6 +3357,7 @@ CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3387,6 +3405,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_8859_2, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3434,6 +3453,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_koi8_r, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3481,6 +3501,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_koi8_u, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3529,6 +3550,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_8859_2, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3576,6 +3598,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_8859_9, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3624,6 +3647,7 @@ CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3672,6 +3696,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_us_ascii, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3719,6 +3744,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_cp1250, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3766,6 +3792,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_cp1251, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3813,6 +3840,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_armscii_8, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3860,6 +3888,7 @@ CHARSET_INFO compiled_charsets[] = { idx_uni_cp1251, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple,/* strnncollsp */ my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ @@ -3906,6 +3935,7 @@ CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, NULL, /* strnncoll */ + NULL, /* strnncollsp */ NULL, /* strnxfrm */ NULL, /* like_range */ NULL, /* wildcmp */ @@ -3913,7 +3943,8 @@ CHARSET_INFO compiled_charsets[] = { NULL, NULL, NULL, - + NULL, + NULL, NULL, /* mb_wc */ NULL, /* wc_mb */ diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c index c0baca808cb..9cc19dc46ef 100644 --- a/strings/ctype-gb2312.c +++ b/strings/ctype-gb2312.c @@ -5704,6 +5704,7 @@ CHARSET_INFO my_charset_gb2312 = NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple, my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_mb, /* wildcmp */ @@ -5711,6 +5712,8 @@ CHARSET_INFO my_charset_gb2312 = ismbchar_gb2312, ismbhead_gb2312, mbcharlen_gb2312, + my_numchars_mb, + my_charpos_mb, my_mb_wc_gb2312, /* mb_wc */ my_wc_mb_gb2312, /* wc_mb */ my_caseup_str_mb, diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c index 5db91d09cc8..42a3686475a 100644 --- a/strings/ctype-gbk.c +++ b/strings/ctype-gbk.c @@ -2608,6 +2608,16 @@ int my_strnncoll_gbk(CHARSET_INFO *cs __attribute__((unused)), return (int) (len1-len2); } +static +int my_strnncollsp_gbk(CHARSET_INFO * cs, + const uchar *s, uint slen, + const uchar *t, uint tlen) +{ + for ( ; slen && my_isspace(cs, s[slen-1]) ; slen--); + for ( ; tlen && my_isspace(cs, t[tlen-1]) ; tlen--); + return my_strnncoll_gbk(cs,s,slen,t,tlen); +} + int my_strnxfrm_gbk(CHARSET_INFO *cs __attribute__((unused)), uchar * dest, uint len, @@ -9891,6 +9901,7 @@ CHARSET_INFO my_charset_gbk = NULL, /* tab_from_uni */ 1, /* strxfrm_multiply */ my_strnncoll_gbk, + my_strnncollsp_gbk, my_strnxfrm_gbk, my_like_range_gbk, my_wildcmp_mb, /* wildcmp */ @@ -9898,6 +9909,8 @@ CHARSET_INFO my_charset_gbk = ismbchar_gbk, ismbhead_gbk, mbcharlen_gbk, + my_numchars_mb, + my_charpos_mb, my_mb_wc_gbk, /* mb_wc */ my_wc_mb_gbk, /* wc_mb */ my_caseup_str_mb, diff --git a/strings/ctype-latin1.c b/strings/ctype-latin1.c index ac1e6dcdc18..518418a9050 100644 --- a/strings/ctype-latin1.c +++ b/strings/ctype-latin1.c @@ -190,6 +190,7 @@ CHARSET_INFO my_charset_latin1 = NULL, /* tab_from_uni */ 2, /* strxfrm_multiply */ my_strnncoll_simple, + my_strnncollsp_simple, my_strnxfrm_simple, my_like_range_simple, my_wildcmp_8bit, /* wildcmp */ @@ -197,6 +198,8 @@ CHARSET_INFO my_charset_latin1 = NULL, /* ismbchar */ NULL, /* ismbhead */ NULL, /* mbcharlen */ + my_numchars_8bit, + my_charpos_8bit, my_mb_wc_latin1, /* mb_wc */ my_wc_mb_latin1, /* wc_mb */ my_caseup_str_8bit, diff --git a/strings/ctype-latin1_de.c b/strings/ctype-latin1_de.c index 22aea5a2cad..93c8ba54bc0 100644 --- a/strings/ctype-latin1_de.c +++ b/strings/ctype-latin1_de.c @@ -295,6 +295,16 @@ static int my_strnncoll_latin1_de(CHARSET_INFO *cs __attribute__((unused)), return s1 < e1 ? 1 : s2 < e2 ? -1 : 0; } +static +int my_strnncollsp_latin1_de(CHARSET_INFO * cs, + const uchar *s, uint slen, + const uchar *t, uint tlen) +{ + for ( ; slen && my_isspace(cs, s[slen-1]) ; slen--); + for ( ; tlen && my_isspace(cs, t[tlen-1]) ; tlen--); + return my_strnncoll_latin1_de(cs,s,slen,t,tlen); +} + static int my_strnxfrm_latin1_de(CHARSET_INFO *cs __attribute__((unused)), uchar * dest, uint len, @@ -336,81 +346,6 @@ static int my_strnxfrm_latin1_de(CHARSET_INFO *cs __attribute__((unused)), return dest - dest_orig; } - -/* - * Calculate min_str and max_str that ranges a LIKE string. - * Arguments: - * ptr IN: Pointer to LIKE string. - * ptr_length IN: Length of LIKE string. - * escape IN: Escape character in LIKE. (Normally '\'). - * No escape characters should appear in min_str or max_str - * res_length IN: Length of min_str and max_str. - * min_str IN/OUT: Smallest case sensitive string that ranges LIKE. - * Should be space padded to res_length. - * max_str IN/OUT: Largest case sensitive string that ranges LIKE. - * Normally padded with the biggest character sort value. - * min_length OUT: Length of min_str without space padding. - * max_length OUT: Length of max_str without space padding. - * - * The function should return 0 if ok and 1 if the LIKE string can't be - * optimized ! - */ - -#define min_sort_char ((char) 0) -#define max_sort_char ((char) 255) - -static my_bool my_like_range_latin1_de(CHARSET_INFO *cs __attribute__((unused)), - const char *ptr, uint ptr_length, - int escape, int w_one, int w_many, - uint res_length, - char *min_str, char *max_str, - uint *min_length, uint *max_length) -{ - const char *end = ptr + ptr_length; - char *min_org = min_str; - char *min_end = min_str + res_length; - - for (; ptr != end && min_str != min_end; ptr++) - { - if (*ptr == escape && ptr + 1 != end) - { - ptr++; /* Skip escape */ - *min_str++ = *max_str++ = *ptr; - continue; - } - if (*ptr == w_one) /* '_' in SQL */ - { - *min_str++ = min_sort_char; - *max_str++ = max_sort_char; - continue; - } - if (*ptr == w_many) /* '%' in SQL */ - { - *min_length = (uint)(min_str - min_org); - *max_length = res_length; - do { - *min_str++ = ' '; /* Because if key compression */ - *max_str++ = max_sort_char; - } while (min_str != min_end); - return 0; - } - *min_str++ = *max_str++ = *ptr; - } - *min_length = *max_length = (uint) (min_str - min_org); - - /* Temporary fix for handling w_one at end of string (key compression) */ - { - char *tmp; - for (tmp= min_str ; tmp > min_org && tmp[-1] == '\0';) - *--tmp=' '; - } - - while (min_str != min_end) - *min_str++ = *max_str++ = ' '; /* Because if key compression */ - return 0; -} - - CHARSET_INFO my_charset_latin1_de = { 31, /* number */ @@ -426,13 +361,16 @@ CHARSET_INFO my_charset_latin1_de = idx_uni_8859_1, /* tab_from_uni */ 2, /* strxfrm_multiply */ my_strnncoll_latin1_de, + my_strnncollsp_latin1_de, my_strnxfrm_latin1_de, - my_like_range_latin1_de, + my_like_range_simple, my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ NULL, /* ismbchar */ NULL, /* ismbhead */ NULL, /* mbcharlen */ + my_numchars_8bit, + my_charpos_8bit, my_mb_wc_8bit, /* mb_wc */ my_wc_mb_8bit, /* wc_mb */ my_caseup_str_8bit, diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index 4c8471d4217..aa4ccdb6af7 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -276,5 +276,31 @@ int my_wildcmp_mb(CHARSET_INFO *cs, return (str != str_end ? 1 : 0); } +uint my_numchars_mb(CHARSET_INFO *cs __attribute__((unused)), + const char *b, const char *e) +{ + register uint32 n=0,mblen; + while (b < e) + { + b+= (mblen= my_ismbchar(cs,b,e)) ? mblen : 1; + ++n; + } + return n; +} + +uint my_charpos_mb(CHARSET_INFO *cs __attribute__((unused)), + const char *b, const char *e, uint pos) +{ + uint mblen; + const char *b0=b; + + while (pos && b<e) + { + b+= (mblen= my_ismbchar(cs,b,e)) ? mblen : 1; + pos--; + } + return b-b0; +} + #endif diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index d7d382a61c3..5fb62d3056f 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -50,6 +50,26 @@ int my_strnncoll_simple(CHARSET_INFO * cs, const uchar *s, uint slen, return (int) (slen-tlen); } + +int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *s, uint slen, + const uchar *t, uint tlen) +{ + uchar *map= cs->sort_order; + int len; + + for ( ; slen && my_isspace(cs, s[slen-1]) ; slen--); + for ( ; tlen && my_isspace(cs, t[tlen-1]) ; tlen--); + + len = ( slen > tlen ) ? tlen : slen; + + while (len--) + { + if (map[*s++] != map[*t++]) + return ((int) map[s[-1]] - (int) map[t[-1]]); + } + return (int) (slen-tlen); +} + void my_caseup_str_8bit(CHARSET_INFO * cs,char *str) { register uchar *map=cs->to_upper; @@ -844,7 +864,7 @@ int my_wildcmp_8bit(CHARSET_INFO *cs, const char *wildstr,const char *wildend, int escape, int w_one, int w_many) { - int result= -1; // Not found, using wildcards + int result= -1; /* Not found, using wildcards */ while (wildstr != wildend) { @@ -854,16 +874,16 @@ int my_wildcmp_8bit(CHARSET_INFO *cs, wildstr++; if (str == str_end || likeconv(cs,*wildstr++) != likeconv(cs,*str++)) - return(1); // No match + return(1); /* No match */ if (wildstr == wildend) - return (str != str_end); // Match if both are at end - result=1; // Found an anchor char + return (str != str_end); /* Match if both are at end */ + result=1; /* Found an anchor char */ } if (*wildstr == w_one) { do { - if (str == str_end) // Skip one char if possible + if (str == str_end) /* Skip one char if possible */ return (result); INC_PTR(cs,str,str_end); } while (++wildstr < wildend && *wildstr == w_one); @@ -871,7 +891,7 @@ int my_wildcmp_8bit(CHARSET_INFO *cs, break; } if (*wildstr == w_many) - { // Found w_many + { /* Found w_many */ uchar cmp; wildstr++; @@ -887,17 +907,17 @@ int my_wildcmp_8bit(CHARSET_INFO *cs, INC_PTR(cs,str,str_end); continue; } - break; // Not a wild character + break; /* Not a wild character */ } if (wildstr == wildend) - return(0); // Ok if w_many is last + return(0); /* Ok if w_many is last */ if (str == str_end) return -1; if ((cmp= *wildstr) == escape && wildstr+1 != wildend) cmp= *++wildstr; - INC_PTR(cs,wildstr,wildend); // This is compared trough cmp + INC_PTR(cs,wildstr,wildend); /* This is compared trough cmp */ cmp=likeconv(cs,cmp); do { @@ -949,22 +969,22 @@ my_bool my_like_range_simple(CHARSET_INFO *cs, { if (*ptr == escape && ptr+1 != end) { - ptr++; // Skip escape + ptr++; /* Skip escape */ *min_str++= *max_str++ = *ptr; continue; } - if (*ptr == w_one) // '_' in SQL + if (*ptr == w_one) /* '_' in SQL */ { - *min_str++='\0'; // This should be min char + *min_str++='\0'; /* This should be min char */ *max_str++=cs->max_sort_char; continue; } - if (*ptr == w_many) // '%' in SQL + if (*ptr == w_many) /* '%' in SQL */ { *min_length= (uint) (min_str - min_org); *max_length=res_length; do { - *min_str++ = ' '; // Because if key compression + *min_str++ = ' '; /* Because if key compression */ *max_str++ = cs->max_sort_char; } while (min_str != min_end); return 0; @@ -981,7 +1001,7 @@ my_bool my_like_range_simple(CHARSET_INFO *cs, } while (min_str != min_end) - *min_str++ = *max_str++ = ' '; // Because if key compression + *min_str++ = *max_str++ = ' '; /* Because if key compression */ return 0; } @@ -1015,4 +1035,18 @@ void my_fill_8bit(CHARSET_INFO *cs __attribute__((unused)), char *s, uint l, int fill) { bfill(s,l,fill); -}
\ No newline at end of file +} + +uint my_numchars_8bit(CHARSET_INFO *cs __attribute__((unused)), + const char *b, const char *e) +{ + return e-b; +} + +uint my_charpos_8bit(CHARSET_INFO *cs __attribute__((unused)), + const char *b __attribute__((unused)), + const char *e __attribute__((unused)), + uint pos) +{ + return pos; +} diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index b666bdf20d2..a266fa71199 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -227,6 +227,16 @@ static int my_strnncoll_sjis(CHARSET_INFO *cs __attribute__((unused)), return len1 - len2; } +static +int my_strnncollsp_sjis(CHARSET_INFO * cs, + const uchar *s, uint slen, + const uchar *t, uint tlen) +{ + for ( ; slen && my_isspace(cs, s[slen-1]) ; slen--); + for ( ; tlen && my_isspace(cs, t[tlen-1]) ; tlen--); + return my_strnncoll_sjis(cs,s,slen,t,tlen); +} + static int my_strnxfrm_sjis(CHARSET_INFO *cs __attribute__((unused)), uchar *dest, uint len, const uchar *src, uint srclen) @@ -4478,6 +4488,7 @@ CHARSET_INFO my_charset_sjis = NULL, /* tab_from_uni */ 1, /* strxfrm_multiply */ my_strnncoll_sjis, + my_strnncollsp_sjis, my_strnxfrm_sjis, my_like_range_sjis, my_wildcmp_mb, /* wildcmp */ @@ -4485,6 +4496,8 @@ CHARSET_INFO my_charset_sjis = ismbchar_sjis, ismbhead_sjis, mbcharlen_sjis, + my_numchars_mb, + my_charpos_mb, my_mb_wc_sjis, /* mb_wc */ my_wc_mb_sjis, /* wc_mb */ my_caseup_str_8bit, diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c index 5461173b766..bf3d332880d 100644 --- a/strings/ctype-tis620.c +++ b/strings/ctype-tis620.c @@ -551,6 +551,17 @@ int my_strnncoll_tis620(CHARSET_INFO *cs __attribute__((unused)), return(i); } +static +int my_strnncollsp_tis620(CHARSET_INFO * cs, + const uchar *s, uint slen, + const uchar *t, uint tlen) +{ + for ( ; slen && my_isspace(cs, s[slen-1]) ; slen--); + for ( ; tlen && my_isspace(cs, t[tlen-1]) ; tlen--); + return my_strnncoll_tis620(cs,s,slen,t,tlen); +} + + /* strnxfrm replacment, convert Thai string to sortable string Arg: Destination buffer, source string, dest length and source length Ret: Conveted string size @@ -700,6 +711,7 @@ CHARSET_INFO my_charset_tis620 = NULL, /* tab_from_uni */ 4, /* strxfrm_multiply */ my_strnncoll_tis620, + my_strnncollsp_tis620, my_strnxfrm_tis620, my_like_range_tis620, my_wildcmp_8bit, /* wildcmp */ @@ -707,6 +719,8 @@ CHARSET_INFO my_charset_tis620 = NULL, /* ismbchar */ NULL, /* ismbhead */ NULL, /* mbcharlen */ + my_numchars_8bit, + my_charpos_8bit, my_mb_wc_8bit, /* mb_wc */ my_wc_mb_8bit, /* wc_mb */ my_caseup_str_8bit, diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c index 268a9e2296e..d39be825ef0 100644 --- a/strings/ctype-ujis.c +++ b/strings/ctype-ujis.c @@ -8444,7 +8444,8 @@ CHARSET_INFO my_charset_ujis = NULL, /* tab_to_uni */ NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ - NULL, /* strnncoll */ + my_strnncoll_simple,/* strnncoll */ + my_strnncollsp_simple, my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_mb, /* wildcmp */ @@ -8452,6 +8453,8 @@ CHARSET_INFO my_charset_ujis = ismbchar_ujis, ismbhead_ujis, mbcharlen_ujis, + my_numchars_mb, + my_charpos_mb, my_mb_wc_euc_jp, /* mb_wc */ my_wc_mb_euc_jp, /* wc_mb */ my_caseup_str_mb, diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index c4c12efe8b2..e63405001f9 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -1855,6 +1855,17 @@ static int my_strnncoll_utf8(CHARSET_INFO *cs, return ( (se-s) - (te-t) ); } +static +int my_strnncollsp_utf8(CHARSET_INFO * cs, + const uchar *s, uint slen, + const uchar *t, uint tlen) +{ + for ( ; slen && my_isspace(cs, s[slen-1]) ; slen--); + for ( ; tlen && my_isspace(cs, t[tlen-1]) ; tlen--); + return my_strnncoll_utf8(cs,s,slen,t,tlen); +} + + static int my_strncasecmp_utf8(CHARSET_INFO *cs, const char *s, const char *t, uint len) { @@ -1979,6 +1990,7 @@ CHARSET_INFO my_charset_utf8 = NULL, /* tab_from_uni */ 1, /* strxfrm_multiply */ my_strnncoll_utf8, /* strnncoll */ + my_strnncollsp_utf8, my_strnxfrm_utf8, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_mb, /* wildcmp */ @@ -1986,6 +1998,8 @@ CHARSET_INFO my_charset_utf8 = my_ismbchar_utf8, /* ismbchar */ my_ismbhead_utf8, /* ismbhead */ my_mbcharlen_utf8, /* mbcharlen */ + my_numchars_mb, + my_charpos_mb, my_utf8_uni, /* mb_wc */ my_uni_utf8, /* wc_mb */ my_caseup_str_utf8, @@ -3052,6 +3066,21 @@ cnv: return (int) (dst-db); } +static +uint my_numchars_ucs2(CHARSET_INFO *cs __attribute__((unused)), + const char *b, const char *e) +{ + return (e-b)/2; +} + +static +uint my_charpos_ucs2(CHARSET_INFO *cs __attribute__((unused)), + const char *b __attribute__((unused)), + const char *e __attribute__((unused)), + uint pos) +{ + return pos*2; +} CHARSET_INFO my_charset_ucs2 = { @@ -3068,6 +3097,7 @@ CHARSET_INFO my_charset_ucs2 = NULL, /* tab_from_uni */ 1, /* strxfrm_multiply */ my_strnncoll_ucs2, /* strnncoll */ + my_strnncoll_ucs2, my_strnxfrm_ucs2, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_mb, /* wildcmp */ @@ -3075,6 +3105,8 @@ CHARSET_INFO my_charset_ucs2 = my_ismbchar_ucs2, /* ismbchar */ my_ismbhead_ucs2, /* ismbhead */ my_mbcharlen_ucs2, /* mbcharlen */ + my_numchars_ucs2, + my_charpos_ucs2, my_ucs2_uni, /* mb_wc */ my_uni_ucs2, /* wc_mb */ my_caseup_str_ucs2, diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c index f5074a4ec0e..467d1ba4c91 100644 --- a/strings/ctype-win1250ch.c +++ b/strings/ctype-win1250ch.c @@ -503,6 +503,17 @@ static int my_strnncoll_win1250ch(CHARSET_INFO *cs __attribute__((unused)), return 0; } +static +int my_strnncollsp_win1250ch(CHARSET_INFO * cs, + const uchar *s, uint slen, + const uchar *t, uint tlen) +{ + for ( ; slen && my_isspace(cs, s[slen-1]) ; slen--); + for ( ; tlen && my_isspace(cs, t[tlen-1]) ; tlen--); + return my_strnncoll_win1250ch(cs,s,slen,t,tlen); +} + + static int my_strnxfrm_win1250ch(CHARSET_INFO * cs __attribute__((unused)), uchar * dest, uint len, const uchar * src, uint srclen) { @@ -644,6 +655,7 @@ CHARSET_INFO my_charset_win1250ch = idx_uni_cp1250, /* tab_from_uni */ 2, /* strxfrm_multiply */ my_strnncoll_win1250ch, + my_strnncollsp_win1250ch, my_strnxfrm_win1250ch, my_like_range_win1250ch, my_wildcmp_8bit, /* wildcmp */ @@ -651,6 +663,8 @@ CHARSET_INFO my_charset_win1250ch = NULL, /* ismbchar */ NULL, /* ismbhead */ NULL, /* mbcharlen */ + my_numchars_8bit, + my_charpos_8bit, my_mb_wc_8bit, /* mb_wc */ my_wc_mb_8bit, /* wc_mb */ my_caseup_str_8bit, diff --git a/tests/client_test.c b/tests/client_test.c index 546c013cfea..dc91bf2cbf1 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -50,6 +50,9 @@ static unsigned int test_count= 0; static unsigned int opt_count= 0; static unsigned int iter_count= 0; +static time_t start_time, end_time; +static double total_time; + #define myheader(str) \ { \ fprintf(stdout,"\n\n#####################################\n"); \ @@ -77,10 +80,10 @@ static void print_error(const char *msg) if (mysql) { if (mysql->server_version) - fprintf(stderr,"\n [MySQL-%s]",mysql->server_version); + fprintf(stdout,"\n [MySQL-%s]",mysql->server_version); else - fprintf(stderr,"\n [MySQL]"); - fprintf(stderr,"[%d] %s\n",mysql_errno(mysql),mysql_error(mysql)); + fprintf(stdout,"\n [MySQL]"); + fprintf(stdout,"[%d] %s\n",mysql_errno(mysql),mysql_error(mysql)); } else if (msg) fprintf(stderr, " [MySQL] %s\n", msg); } @@ -90,11 +93,11 @@ static void print_st_error(MYSQL_STMT *stmt, const char *msg) if (stmt) { if (stmt->mysql && stmt->mysql->server_version) - fprintf(stderr,"\n [MySQL-%s]",stmt->mysql->server_version); + fprintf(stdout,"\n [MySQL-%s]",stmt->mysql->server_version); else - fprintf(stderr,"\n [MySQL]"); + fprintf(stdout,"\n [MySQL]"); - fprintf(stderr,"[%d] %s\n",mysql_stmt_errno(stmt), + fprintf(stdout,"[%d] %s\n",mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); } else if (msg) fprintf(stderr, " [MySQL] %s\n", msg); @@ -173,6 +176,7 @@ static void client_connect() { myerror("connection failed"); mysql_close(mysql); + fprintf(stdout,"\n Check the connection options using --help or -?\n"); exit(0); } fprintf(stdout," OK"); @@ -438,7 +442,7 @@ uint my_stmt_result(const char *query, unsigned long length) uint row_count; int rc; - fprintf(stdout,"\n\n %s \n", query); + fprintf(stdout,"\n\n %s", query); stmt= mysql_prepare(mysql,query,length); mystmt_init(stmt); @@ -1072,7 +1076,7 @@ static void test_prepare() myquery(rc); /* test the results now, only one row should exists */ - myassert(tiny_data == (int) my_stmt_result("SELECT * FROM my_prepare",50)); + myassert(tiny_data == (char) my_stmt_result("SELECT * FROM my_prepare",50)); stmt = mysql_prepare(mysql,"SELECT * FROM my_prepare",50); mystmt_init(stmt); @@ -1238,8 +1242,7 @@ static void test_null() { MYSQL_STMT *stmt; int rc; - int nData=1; - MYSQL_RES *result; + uint nData; MYSQL_BIND bind[2]; my_bool is_null[2]; @@ -1268,33 +1271,69 @@ static void test_null() bind[0].buffer_type=MYSQL_TYPE_LONG; bind[0].is_null= &is_null[0]; is_null[0]= 1; - bind[1]=bind[0]; /* string data */ + bind[1]=bind[0]; rc = mysql_bind_param(stmt,bind); mystmt(stmt, rc); /* now, execute the prepared statement to insert 10 records.. */ - for (nData=0; nData<9; nData++) + for (nData=0; nData<10; nData++) { rc = mysql_execute(stmt); mystmt(stmt, rc); } + + /* Re-bind with MYSQL_TYPE_NULL */ + bind[0].buffer_type= MYSQL_TYPE_NULL; + is_null[0]= 0; /* reset */ + bind[1]= bind[0]; + + rc = mysql_bind_param(stmt,bind); + mystmt(stmt,rc); + + for (nData=0; nData<10; nData++) + { + rc = mysql_execute(stmt); + mystmt(stmt, rc); + } + mysql_stmt_close(stmt); /* now fetch the results ..*/ rc = mysql_commit(mysql); myquery(rc); - /* test the results now, only one row should exists */ - rc = mysql_query(mysql,"SELECT * FROM test_null"); - myquery(rc); + nData*= 2; + myassert(nData == my_stmt_result("SELECT * FROM test_null", 30)); - /* get the result */ - result = mysql_store_result(mysql); - mytest(result); + /* Fetch results */ + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (char *)&nData; /* this buffer won't be altered */ + bind[0].length= 0; + bind[1]= bind[0]; + bind[0].is_null= &is_null[0]; + bind[1].is_null= &is_null[1]; - myassert(nData == my_process_result_set(result)); - mysql_free_result(result); + stmt = mysql_prepare(mysql,"SELECT * FROM test_null",30); + mystmt_init(stmt); + + rc = mysql_execute(stmt); + mystmt(stmt,rc); + + rc = mysql_bind_result(stmt,bind); + mystmt(stmt,rc); + + rc= 0; + is_null[0]= is_null[1]= 0; + while (mysql_fetch(stmt) != MYSQL_NO_DATA) + { + myassert(is_null[0]); + myassert(is_null[1]); + rc++; + is_null[0]= is_null[1]= 0; + } + myassert(rc == (int)nData); + mysql_stmt_close(stmt); } @@ -1636,8 +1675,13 @@ static void test_select_show() mysql_autocommit(mysql,TRUE); - strmov(query,"SELECT * FROM mysql.host"); - stmt = mysql_prepare(mysql, query, strlen(query)); + rc = mysql_query(mysql, "DROP TABLE IF EXISTS test_show"); + myquery(rc); + + rc = mysql_query(mysql, "CREATE TABLE test_show(id int(4) NOT NULL, name char(2))"); + myquery(rc); + + stmt = mysql_prepare(mysql, "show columns from test_show", 30); mystmt_init(stmt); verify_param_count(stmt,0); @@ -1646,7 +1690,28 @@ static void test_select_show() mystmt(stmt, rc); my_process_stmt_result(stmt); + mysql_stmt_close(stmt); + + stmt = mysql_prepare(mysql, "show tables from mysql like ?", 50); + mystmt_init_r(stmt); + + strxmov(query,"show tables from ", current_db, " like \'test_show\'", NullS); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + my_process_stmt_result(stmt); + mysql_stmt_close(stmt); + + stmt = mysql_prepare(mysql, "describe test_show", 30); + mystmt_init(stmt); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + my_process_stmt_result(stmt); mysql_stmt_close(stmt); } @@ -4362,6 +4427,9 @@ static void test_multi_query() const char *query= "DROP TABLE IF EXISTS test_multi_tab;\ CREATE TABLE test_multi_tab(id int,name char(20));\ + INSERT INTO test_multi_tab(xxxx) VALUES(10);\ + UPDATE test_multi_tab SET id=10 WHERE unkown_col=10;\ + CREATE TABLE test_multi_tab(id int,name char(20));\ INSERT INTO test_multi_tab(id) VALUES(10),(20);\ INSERT INTO test_multi_tab VALUES(20,'insert;comma');\ SELECT * FROM test_multi_tab;\ @@ -4370,14 +4438,20 @@ static void test_multi_query() DELETE FROM test_multi_tab WHERE name='new;name';\ SELECT * FROM test_multi_tab;\ DELETE FROM test_multi_tab WHERE id=10;\ - SELECT * FROM test_multi_tab"; - uint count, rows[10]={0,2,1,3,0,2,2,1,1,0}; - + SELECT * FROM test_multi_tab;\ + DROP TABLE test_multi_tab;\ + DROP TABLE test_multi_tab;\ + DROP TABLE IF EXISTS test_multi_tab"; + uint count, rows[16]={0,1054,1054,1050,2,1,3,1054,2,2,1,1,0,0,1051,0}, exp_value; + myheader("test_multi_query"); rc = mysql_query(mysql, query); /* syntax error */ myquery_r(rc); + myassert(0 == mysql_next_result(mysql)); + myassert(0 == mysql_more_results(mysql)); + if (!(l_mysql = mysql_init(NULL))) { fprintf(stdout,"\n mysql_init() failed"); @@ -4396,19 +4470,25 @@ static void test_multi_query() rc = mysql_query(mysql, query); myquery(rc); - count= 0; - while (mysql_more_results(mysql) && count < sizeof(rows)/sizeof(uint)) + count= exp_value= 0; + while (mysql_more_results(mysql) && count < array_elements(rows)) { - fprintf(stdout,"\n query %d", count); + fprintf(stdout,"\n Query %d: ", count); if ((rc= mysql_next_result(mysql))) - fprintf(stdout, "\n\t failed(%s)", mysql_error(mysql)); + { + exp_value= mysql_errno(mysql); + fprintf(stdout, "ERROR %d: %s", exp_value, mysql_error(mysql)); + } else - fprintf(stdout,"\n\t affected rows: %lld", mysql_affected_rows(mysql)); - if ((result= mysql_store_result(mysql))) - my_process_result_set(result); - if (!rc) - myassert(rows[count] == (uint)mysql_affected_rows(mysql)); - count++; + { + if ((result= mysql_store_result(mysql))) + my_process_result_set(result); + else + fprintf(stdout,"OK, %d row(s) affected, %d warning(s)", exp_value, + mysql_warning_count(mysql)); + exp_value= (uint) mysql_affected_rows(mysql); + } + myassert(rows[count++] == exp_value); } mysql= org_mysql; } @@ -4865,7 +4945,7 @@ static void test_bind_date_conv(uint row_count) for (i= 0; i < array_elements(bind); i++) { fprintf(stdout, "\n"); - fprintf(stdout,"time[%d]: %02d-%02d-%02d %02d:%02d:%02d.%02lu", + fprintf(stdout," time[%d]: %02d-%02d-%02d %02d:%02d:%02d.%02lu", i, tm[i].year, tm[i].month, tm[i].day, tm[i].hour, tm[i].minute, tm[i].second, tm[i].second_part); @@ -5196,6 +5276,157 @@ static void test_buffers() mysql_stmt_close(stmt); } +/* + Test the direct query execution in the middle of open stmts +*/ +static void test_open_direct() +{ + MYSQL_STMT *stmt; + MYSQL_RES *result; + int rc; + + myheader("test_open_direct"); + + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_open_direct"); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_open_direct(id int, name char(6))"); + myquery(rc); + + stmt = mysql_prepare(mysql,"INSERT INTO test_open_direct values(10,'mysql')", 100); + mystmt_init(stmt); + + rc = mysql_query(mysql, "SELECT * FROM test_open_direct"); + myquery(rc); + + result = mysql_store_result(mysql); + mytest(result); + + myassert(0 == my_process_result_set(result)); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + fprintf(stdout, "\n total affected rows: %lld", mysql_stmt_affected_rows(stmt)); + myassert(1 == mysql_stmt_affected_rows(stmt)); + + rc = mysql_query(mysql, "SELECT * FROM test_open_direct"); + myquery(rc); + + result = mysql_store_result(mysql); + mytest(result); + + myassert(1 == my_process_result_set(result)); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + fprintf(stdout, "\n total affected rows: %lld", mysql_stmt_affected_rows(stmt)); + myassert(1 == mysql_stmt_affected_rows(stmt)); + + rc = mysql_query(mysql, "SELECT * FROM test_open_direct"); + myquery(rc); + + result = mysql_store_result(mysql); + mytest(result); + + myassert(2 == my_process_result_set(result)); + mysql_stmt_close(stmt); + + /* run a direct query in the middle of a fetch */ + stmt= mysql_prepare(mysql,"SELECT * FROM test_open_direct",100); + mystmt_init(stmt); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt, rc); + + rc = mysql_query(mysql,"INSERT INTO test_open_direct(id) VALUES(20)"); + myquery_r(rc); + + rc = mysql_stmt_close(stmt); + mystmt(stmt, rc); + + rc = mysql_query(mysql,"INSERT INTO test_open_direct(id) VALUES(20)"); + myquery(rc); + + /* run a direct query with store result */ + stmt= mysql_prepare(mysql,"SELECT * FROM test_open_direct",100); + mystmt_init(stmt); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_stmt_store_result(stmt); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt, rc); + + rc = mysql_query(mysql,"drop table test_open_direct"); + myquery(rc); + + rc = mysql_stmt_close(stmt); + mystmt(stmt, rc); +} + +/* + To test fetch without prior bound buffers +*/ +static void test_fetch_nobuffs() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[4]; + char str[4][50]; + int rc; + + myheader("test_fetch_nobuffs"); + + stmt = mysql_prepare(mysql,"SELECT DATABASE(), CURRENT_USER(), CURRENT_DATE(), CURRENT_TIME()",100); + mystmt_init(stmt); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = 0; + while (mysql_fetch(stmt) != MYSQL_NO_DATA) + rc++; + fprintf(stdout, "\n total rows: %d", rc); + myassert(rc == 1); + + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (char *)str[0]; + bind[0].is_null= 0; + bind[0].length= 0; + bind[0].buffer_length= sizeof(str[0]); + bind[1]= bind[2]= bind[3]= bind[0]; + bind[1].buffer= (char *)str[1]; + bind[2].buffer= (char *)str[2]; + bind[3].buffer= (char *)str[3]; + + rc = mysql_bind_result(stmt, bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = 0; + while (mysql_fetch(stmt) != MYSQL_NO_DATA) + { + rc++; + fprintf(stdout, "\n CURRENT_DATABASE(): %s", str[0]); + fprintf(stdout, "\n CURRENT_USER() : %s", str[1]); + fprintf(stdout, "\n CURRENT_DATE() : %s", str[2]); + fprintf(stdout, "\n CURRENT_TIME() : %s", str[3]); + } + fprintf(stdout, "\n total rows: %d", rc); + myassert(rc == 1); + + mysql_stmt_close(stmt); +} + static struct my_option myctest_long_options[] = { {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, @@ -5225,6 +5456,7 @@ static void usage(void) /* * show the usage string when the user asks for this */ + putc('\n',stdout); puts("***********************************************************************\n"); puts(" Test for client-server protocol 4.1"); puts(" By Monty & Venu \n"); @@ -5251,7 +5483,7 @@ static void usage(void) #endif fprintf(stdout,"\ -t, --count=... Execute the test count times.\n"); - fprintf(stdout,"*********************************************************************\n"); + puts("***********************************************************************\n"); } static my_bool @@ -5300,26 +5532,42 @@ static void get_options(int argc, char **argv) return; } +/* + Print the test output on successful execution before exiting +*/ + +static void print_test_output() +{ + fprintf(stdout,"\n\n"); + fprintf(stdout,"All '%d' tests were successful (in '%d' iterations)", + test_count-1, opt_count); + fprintf(stdout,"\n Total execution time: %g SECS", total_time); + if (opt_count > 1) + fprintf(stdout," (Avg: %g SECS)", total_time/opt_count); + + fprintf(stdout,"\n\n!!! SUCCESS !!!\n"); +} + /******************************************************** * main routine * *********************************************************/ int main(int argc, char **argv) { - time_t start_time, end_time; - double total_time= 0; - MY_INIT(argv[0]); get_options(argc,argv); client_connect(); /* connect to server */ + total_time= 0; for (iter_count=1; iter_count <= opt_count; iter_count++) { /* Start of tests */ test_count= 1; start_time= time((time_t *)0); - + + test_fetch_nobuffs(); /* to fecth without prior bound buffers */ + test_open_direct(); /* direct execution in the middle of open stmts */ test_fetch_null(); /* to fetch null data */ test_fetch_date(); /* to fetch date,time and timestamp */ test_fetch_str(); /* to fetch string to all types */ @@ -5399,13 +5647,8 @@ int main(int argc, char **argv) } client_disconnect(); /* disconnect from server */ - fprintf(stdout,"\n\nAll '%d' tests were successful (in '%d' iterations)", - test_count-1, opt_count); - fprintf(stdout,"\n Total execution time: %g SECS", total_time); - if (opt_count > 1) - fprintf(stdout," (Avg: %g SECS)", total_time/opt_count); + print_test_output(); - fprintf(stdout,"\n\nSUCCESS !!!\n"); return(0); } |