summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqlbinlog.cc1
-rw-r--r--include/config-win.h6
-rw-r--r--include/m_ctype.h13
-rw-r--r--include/my_sys.h1
-rw-r--r--innobase/include/os0proc.h2
-rw-r--r--innobase/os/os0proc.c20
-rw-r--r--innobase/srv/srv0start.c2
-rw-r--r--libmysql/errmsg.c6
-rw-r--r--libmysql/libmysql.c70
-rw-r--r--mysql-test/r/rpl_user_variables.result78
-rw-r--r--mysql-test/t/rpl_user_variables.test39
-rw-r--r--mysys/charset.c3
-rw-r--r--sql/item_func.cc53
-rw-r--r--sql/item_strfunc.cc41
-rw-r--r--sql/log.cc17
-rw-r--r--sql/log_event.cc242
-rw-r--r--sql/log_event.h50
-rw-r--r--sql/sql_class.cc12
-rw-r--r--sql/sql_class.h13
-rw-r--r--sql/sql_parse.cc10
-rw-r--r--sql/sql_string.cc103
-rw-r--r--sql/sql_udf.cc49
-rw-r--r--sql/sql_udf.h7
-rw-r--r--sql/sql_yacc.yy9
-rw-r--r--sql/unireg.h2
-rw-r--r--strings/ctype-big5.c13
-rw-r--r--strings/ctype-bin.c3
-rw-r--r--strings/ctype-czech.c15
-rw-r--r--strings/ctype-euc_kr.c3
-rw-r--r--strings/ctype-extra.c33
-rw-r--r--strings/ctype-gb2312.c3
-rw-r--r--strings/ctype-gbk.c13
-rw-r--r--strings/ctype-latin1.c3
-rw-r--r--strings/ctype-latin1_de.c90
-rw-r--r--strings/ctype-mb.c26
-rw-r--r--strings/ctype-simple.c66
-rw-r--r--strings/ctype-sjis.c13
-rw-r--r--strings/ctype-tis620.c14
-rw-r--r--strings/ctype-ujis.c5
-rw-r--r--strings/ctype-utf8.c32
-rw-r--r--strings/ctype-win1250ch.c14
-rw-r--r--tests/client_test.c337
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= &param->buffer_length;
+ param->length= &param_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);
}