diff options
48 files changed, 2878 insertions, 1660 deletions
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index ad97d5b1442..d73b28863ba 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -4502,8 +4502,8 @@ stmt_fetch_row(MYSQL_STMT *stmt, uchar **row) MYSQL_BIND *bind, *end; uchar *null_ptr= (uchar*) *row, bit; - *row+= (stmt->field_count+7)/8; - bit=1; + row+= (stmt->field_count+9)/8; + bit= 4; /* First 2 bits are reserved */ /* Copy complete row to application buffers */ for (bind= stmt->bind, end= (MYSQL_BIND *) bind + stmt->field_count; diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index ea47126a4d5..daf65cb2f80 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -44,7 +44,7 @@ sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \ item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \ item_uniq.cc item_subselect.cc item_row.cc\ key.cc lock.cc log.cc log_event.cc mf_iocache.cc\ - mini_client.cc net_pkg.cc net_serv.cc opt_ft.cc opt_range.cc \ + mini_client.cc protocol.cc net_serv.cc opt_ft.cc opt_range.cc \ opt_sum.cc procedure.cc records.cc sql_acl.cc \ repl_failsafe.cc slave.cc sql_load.cc sql_olap.cc \ sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \ diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index ec37c9a5763..18241a8fcc1 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -10,10 +10,10 @@ CASE "c" when "a" then 1 when "b" then 2 ELSE 3 END 3 select CASE BINARY "b" when "a" then 1 when "B" then 2 WHEN "b" then "ok" END; CASE BINARY "b" when "a" then 1 when "B" then 2 WHEN "b" then "ok" END -ok +0 select CASE "b" when "a" then 1 when binary "B" then 2 WHEN "b" then "ok" END; CASE "b" when "a" then 1 when binary "B" then 2 WHEN "b" then "ok" END -ok +0 select CASE concat("a","b") when concat("ab","") then "a" when "b" then "b" end; CASE concat("a","b") when concat("ab","") then "a" when "b" then "b" end a diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index 572b32c171c..2309de2354b 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -24,10 +24,10 @@ cast("A" as binary) = "a" cast(BINARY "a" as CHAR) = "A" 0 1 select cast("2001-1-1" as DATE), cast("2001-1-1" as DATETIME); cast("2001-1-1" as DATE) cast("2001-1-1" as DATETIME) -2001-1-1 2001-1-1 +2001-01-01 2001-01-01 00:00:00 select cast("1:2:3" as TIME); cast("1:2:3" as TIME) -1:2:3 +1:02:03 select cast("2001-1-1" as date) = "2001-01-01"; cast("2001-1-1" as date) = "2001-01-01" 0 diff --git a/sql/Makefile.am b/sql/Makefile.am index c5af51e8397..245e4c5d258 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -64,7 +64,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ thr_malloc.cc item_create.cc item_subselect.cc \ item_row.cc \ field.cc key.cc sql_class.cc sql_list.cc \ - net_serv.cc net_pkg.cc lock.cc my_lock.c \ + net_serv.cc protocol.cc lock.cc my_lock.c \ sql_string.cc sql_manager.cc sql_map.cc \ mysqld.cc password.c hash_filo.cc hostname.cc \ convert.cc set_var.cc sql_parse.cc sql_yacc.yy \ diff --git a/sql/field.cc b/sql/field.cc index bc795e3d5cb..a412c2cb146 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -192,17 +192,12 @@ void Field::copy_from_tmp(int row_offset) } -bool Field::send(THD *thd, String *packet) +bool Field::send_binary(Protocol *protocol) { - if (is_null()) - return net_store_null(packet); char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),default_charset_info); val_str(&tmp,&tmp); - CONVERT *convert; - if ((convert=thd->variables.convert_set)) - return convert->store(packet,tmp.ptr(),tmp.length()); - return net_store_data(packet,tmp.ptr(),tmp.length()); + return protocol->store(tmp.ptr(), tmp.length()); } @@ -1066,6 +1061,10 @@ String *Field_tiny::val_str(String *val_buffer, return val_buffer; } +bool Field_tiny::send_binary(Protocol *protocol) +{ + return protocol->store_tiny((longlong) (int8) ptr[0]); +} int Field_tiny::cmp(const char *a_ptr, const char *b_ptr) { @@ -1277,6 +1276,7 @@ longlong Field_short::val_int(void) return unsigned_flag ? (longlong) (unsigned short) j : (longlong) j; } + String *Field_short::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { @@ -1302,6 +1302,12 @@ String *Field_short::val_str(String *val_buffer, } +bool Field_short::send_binary(Protocol *protocol) +{ + return protocol->store_short(Field_short::val_int()); +} + + int Field_short::cmp(const char *a_ptr, const char *b_ptr) { short a,b; @@ -1526,6 +1532,12 @@ String *Field_medium::val_str(String *val_buffer, } +bool Field_medium::send_binary(Protocol *protocol) +{ + return protocol->store_long(Field_medium::val_int()); +} + + int Field_medium::cmp(const char *a_ptr, const char *b_ptr) { long a,b; @@ -1759,6 +1771,11 @@ String *Field_long::val_str(String *val_buffer, } +bool Field_long::send_binary(Protocol *protocol) +{ + return protocol->store_long(Field_long::val_int()); +} + int Field_long::cmp(const char *a_ptr, const char *b_ptr) { int32 a,b; @@ -1971,6 +1988,12 @@ String *Field_longlong::val_str(String *val_buffer, } +bool Field_longlong::send_binary(Protocol *protocol) +{ + return protocol->store_longlong(Field_longlong::val_int(), unsigned_flag); +} + + int Field_longlong::cmp(const char *a_ptr, const char *b_ptr) { longlong a,b; @@ -2285,6 +2308,12 @@ void Field_float::sort_string(char *to,uint length __attribute__((unused))) } +bool Field_float::send_binary(Protocol *protocol) +{ + return protocol->store((float) Field_float::val_real(), dec, (String*) 0); +} + + void Field_float::sql_type(String &res) const { if (dec == NOT_FIXED_DEC) @@ -2482,6 +2511,11 @@ String *Field_double::val_str(String *val_buffer, return val_buffer; } +bool Field_double::send_binary(Protocol *protocol) +{ + return protocol->store((float) Field_double::val_real(), dec, (String*) 0); +} + int Field_double::cmp(const char *a_ptr, const char *b_ptr) { @@ -2804,6 +2838,7 @@ String *Field_timestamp::val_str(String *val_buffer, return val_buffer; } + bool Field_timestamp::get_date(TIME *ltime, bool fuzzydate) { long temp; @@ -2843,6 +2878,15 @@ bool Field_timestamp::get_time(TIME *ltime) return Field_timestamp::get_date(ltime,0); } + +bool Field_timestamp::send_binary(Protocol *protocol) +{ + TIME tm; + Field_timestamp::get_date(&tm, 1); + return protocol->store(&tm); +} + + int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr) { int32 a,b; @@ -2861,6 +2905,7 @@ int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr) return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0; } + void Field_timestamp::sort_string(char *to,uint length __attribute__((unused))) { #ifdef WORDS_BIGENDIAN @@ -3051,6 +3096,17 @@ bool Field_time::get_time(TIME *ltime) return 0; } + +bool Field_time::send_binary(Protocol *protocol) +{ + TIME tm; + Field_time::get_time(&tm); + tm.day= tm.hour/3600; // Move hours to days + tm.hour-= tm.day*3600; + return protocol->store(&tm); +} + + int Field_time::cmp(const char *a_ptr, const char *b_ptr) { int32 a,b; @@ -3946,19 +4002,15 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) ThNormalize((uchar *) ptr+2, field_length, (uchar *) from, length); } #else - if (length <= field_length) - { - memcpy(ptr+2,from,length); - } - else + if (length > field_length) { length=field_length; - memcpy(ptr+2,from,field_length); current_thd->cuted_fields++; error= 1; } + memcpy(ptr+2,from,length); #endif /* USE_TIS620 */ - int2store(ptr,length); + int2store(ptr, length); return error; } @@ -4155,6 +4207,28 @@ uint Field_varstring::max_packed_col_length(uint max_length) return (max_length > 255 ? 2 : 1)+max_length; } +void Field_varstring::get_key_image(char *buff, uint length, imagetype type) +{ + length-= HA_KEY_BLOB_LENGTH; + uint f_length=uint2korr(ptr); + if (f_length > length) + f_length= length; + int2store(buff,length); + memcpy(buff+2,ptr+2,length); +#ifdef HAVE_purify + if (f_length < length) + bzero(buff+2+f_length, (length-f_length)); +#endif +} + +void Field_varstring::set_key_image(char *buff,uint length) +{ + length=uint2korr(buff); // Real length is here + (void) Field_varstring::store(buff+2, length, default_charset_info); +} + + + /**************************************************************************** ** blob type ** A blob is saved as a length and a pointer. The length is stored in the @@ -4422,7 +4496,6 @@ void Field_blob::get_key_image(char *buff,uint length, imagetype type) return; } - length-=HA_KEY_BLOB_LENGTH; if ((uint32) length > blob_length) { #ifdef HAVE_purify diff --git a/sql/field.h b/sql/field.h index 16929a363dd..49f75a3d471 100644 --- a/sql/field.h +++ b/sql/field.h @@ -27,10 +27,12 @@ #define NOT_FIXED_DEC 31 class Send_field; +class Protocol; struct st_cache_field; void field_conv(Field *to,Field *from); -class Field { +class Field +{ Field(const Item &); /* Prevent use of these */ void operator=(Field &); public: @@ -164,7 +166,7 @@ public: ptr-=row_offset; return tmp; } - bool send(THD *thd, String *packet); + bool send_binary(Protocol *protocol); virtual char *pack(char* to, const char *from, uint max_length=~(uint) 0) { uint32 length=pack_length(); @@ -268,11 +270,11 @@ public: void set_charset(CHARSET_INFO *charset) { field_charset=charset; } bool binary() const { return field_charset->state & MY_CS_BINSORT ? 1 : 0; } inline int cmp_image(char *buff,uint length) - { - if (binary()) - return memcmp(ptr,buff,length); - else - return my_strncasecmp(field_charset,ptr,buff,length); + { + if (binary()) + return memcmp(ptr,buff,length); + else + return my_strncasecmp(field_charset,ptr,buff,length); } friend class create_field; }; @@ -291,7 +293,7 @@ public: {} enum_field_types type() const { return FIELD_TYPE_DECIMAL;} enum ha_base_keytype key_type() const - { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } + { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } void reset(void); int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); @@ -329,6 +331,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 1; } @@ -358,6 +361,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 2; } @@ -387,6 +391,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 3; } @@ -420,6 +425,7 @@ public: void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; } double val_real(void); longlong val_int(void); + bool send_binary(Protocol *protocol); String *val_str(String*,String *); int cmp(const char *,const char*); void sort_string(char *buff,uint length); @@ -457,6 +463,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 8; } @@ -485,6 +492,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return sizeof(float); } @@ -517,6 +525,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return sizeof(double); } @@ -567,6 +576,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 4; } @@ -610,6 +620,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); void sql_type(String &str) const; }; @@ -636,6 +647,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 4; } @@ -664,6 +676,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 3; } @@ -697,6 +710,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); bool get_time(TIME *ltime); int cmp(const char *,const char*); void sort_string(char *buff,uint length); @@ -732,6 +746,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 8; } @@ -772,6 +787,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); void sql_type(String &str) const; @@ -812,8 +828,11 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); + void get_key_image(char *buff,uint length, imagetype type); + void set_key_image(char *buff,uint length); void sql_type(String &str) const; char *pack(char *to, const char *from, uint max_length=~(uint) 0); const char *unpack(char* to, const char *from); @@ -852,6 +871,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); int cmp(const char *a, uint32 a_length, const char *b, uint32 b_length); int cmp_offset(uint offset); @@ -957,6 +977,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return (uint32) packlength; } diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 8edb63b23d6..1b8a2d9b3f8 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -231,10 +231,9 @@ int berkeley_rollback(THD *thd, void *trans) } -int berkeley_show_logs(THD *thd) +int berkeley_show_logs(Protocol *protocol) { char **all_logs, **free_logs, **a, **f; - String *packet= &thd->packet; int error=1; MEM_ROOT show_logs_root; MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); @@ -243,8 +242,9 @@ int berkeley_show_logs(THD *thd) init_alloc_root(&show_logs_root, 1024, 1024); my_pthread_setspecific_ptr(THR_MALLOC,&show_logs_root); - if ((error= db_env->log_archive(db_env, &all_logs, DB_ARCH_ABS | DB_ARCH_LOG)) - || (error= db_env->log_archive(db_env, &free_logs, DB_ARCH_ABS))) + if ((error= db_env->log_archive(db_env, &all_logs, + DB_ARCH_ABS | DB_ARCH_LOG)) || + (error= db_env->log_archive(db_env, &free_logs, DB_ARCH_ABS))) { DBUG_PRINT("error", ("log_archive failed (error %d)", error)); db_env->err(db_env, error, "log_archive: DB_ARCH_ABS"); @@ -257,18 +257,18 @@ int berkeley_show_logs(THD *thd) { for (a = all_logs, f = free_logs; *a; ++a) { - packet->length(0); - net_store_data(packet,*a); - net_store_data(packet,"BDB"); + protocol->prepare_for_resend(); + protocol->store(*a); + protocol->store("BDB", 3); if (f && *f && strcmp(*a, *f) == 0) { - ++f; - net_store_data(packet, SHOW_LOG_STATUS_FREE); + f++; + protocol->store(SHOW_LOG_STATUS_FREE); } else - net_store_data(packet, SHOW_LOG_STATUS_INUSE); + protocol->store(SHOW_LOG_STATUS_INUSE); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + if (protocol->write()) { error=1; goto err; @@ -2065,8 +2065,7 @@ void ha_berkeley::print_error(int error, myf errflag) static void print_msg(THD *thd, const char *table_name, const char *op_name, const char *msg_type, const char *fmt, ...) { - String* packet = &thd->packet; - packet->length(0); + Protocol *protocol= thd->protocol; char msgbuf[256]; msgbuf[0] = 0; va_list args; @@ -2074,15 +2073,14 @@ static void print_msg(THD *thd, const char *table_name, const char *op_name, my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia - DBUG_PRINT(msg_type,("message: %s",msgbuf)); - net_store_data(packet, table_name); - net_store_data(packet, op_name); - net_store_data(packet, msg_type); - net_store_data(packet, msgbuf); - if (my_net_write(&thd->net, (char*)thd->packet.ptr(), - thd->packet.length())) + protocol->prepare_for_resend(); + protocol->store(table_name); + protocol->store(op_name); + protocol->store(msg_type); + protocol->store(msgbuf); + if (protocol->write()) thd->killed=1; } #endif diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index f2a81d123f1..dfdd12470d6 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -180,4 +180,4 @@ bool berkeley_end(void); bool berkeley_flush_logs(void); int berkeley_commit(THD *thd, void *trans); int berkeley_rollback(THD *thd, void *trans); -int berkeley_show_logs(THD *thd); +int berkeley_show_logs(Protocol *protocol); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 14810bada31..8f933085066 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -3922,9 +3922,8 @@ innodb_show_status( /*===============*/ THD* thd) /* in: the MySQL query thread of the caller */ { - String* packet = &thd->packet; char* buf; - + Protocol *protocol= thd->protocol; DBUG_ENTER("innodb_show_status"); if (innodb_skip) { @@ -3945,22 +3944,17 @@ innodb_show_status( field_list.push_back(new Item_empty_string("Status", strlen(buf))); - if(send_fields(thd, field_list, 1)) { + if (protocol->send_fields(&field_list, 1)) + { DBUG_RETURN(-1); } - packet->length(0); - - net_store_data(packet, buf); - - if (my_net_write(&thd->net, (char*)thd->packet.ptr(), - packet->length())) { - ut_free(buf); - - DBUG_RETURN(-1); - } - + protocol->prepare_for_resend(); + protocol->store(buf, strlen(buf)); ut_free(buf); + + if (protocol->write()) + DBUG_RETURN(-1); send_eof(thd); diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index ae71e362875..67fddf34d5c 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -50,14 +50,12 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type, const char *fmt, va_list args) { THD* thd = (THD*)param->thd; - String* packet = &thd->packet; - uint length; + Protocol *protocol= thd->protocol; + uint length, msg_length; char msgbuf[MI_MAX_MSG_BUF]; char name[NAME_LEN*2+2]; - packet->length(0); - msgbuf[0] = 0; // healthy paranoia ? - my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); + msg_length= my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia DBUG_PRINT(msg_type,("message: %s",msgbuf)); @@ -67,19 +65,20 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type, sql_print_error(msgbuf); return; } - if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR | T_AUTO_REPAIR)) + if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR | + T_AUTO_REPAIR)) { my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME)); return; } length=(uint) (strxmov(name, param->db_name,".",param->table_name,NullS) - name); - net_store_data(packet, name, length); - net_store_data(packet, param->op_name); - net_store_data(packet, msg_type); - - net_store_data(packet, msgbuf); - if (my_net_write(&thd->net, (char*)thd->packet.ptr(), thd->packet.length())) + protocol->prepare_for_resend(); + protocol->store(name, length); + protocol->store(param->op_name); + protocol->store(msg_type); + protocol->store(msgbuf, msg_length); + if (protocol->write()) sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n", msgbuf); return; diff --git a/sql/item.cc b/sql/item.cc index 5e74820a3f8..2d90db0cc5d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -22,6 +22,7 @@ #include "mysql_priv.h" #include <m_ctype.h> #include "my_dir.h" +#include <assert.h> /***************************************************************************** ** Item functions @@ -372,12 +373,6 @@ int Item_param::save_in_field(Field *field, bool no_conversions) } -void Item_param::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_STRING); -} - - double Item_param::val() { switch (item_result_type) { @@ -630,66 +625,26 @@ void Item::init_make_field(Send_field *tmp_field, tmp_field->flags |= UNSIGNED_FLAG; } -/* ARGSUSED */ -void Item_field::make_field(Send_field *tmp_field) -{ - field->make_field(tmp_field); - if (name) - tmp_field->col_name=name; // Use user supplied name -} - -void Item_int::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_LONGLONG); -} - -void Item_uint::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_LONGLONG); - tmp_field->flags|= UNSIGNED_FLAG; - unsigned_flag=1; -} - -void Item_real::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_DOUBLE); -} - -void Item_string::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_STRING); -} - -void Item_datetime::make_field(Send_field *tmp_field) +void Item::make_field(Send_field *tmp_field) { - init_make_field(tmp_field,FIELD_TYPE_DATETIME); + init_make_field(tmp_field, field_type()); } - -void Item_null::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_NULL); - tmp_field->length=4; -} - - -void Item_func::make_field(Send_field *tmp_field) +enum_field_types Item::field_type() const { - init_make_field(tmp_field, ((result_type() == STRING_RESULT) ? - FIELD_TYPE_VAR_STRING : - (result_type() == INT_RESULT) ? - FIELD_TYPE_LONGLONG : FIELD_TYPE_DOUBLE)); + return ((result_type() == STRING_RESULT) ? FIELD_TYPE_VAR_STRING : + (result_type() == INT_RESULT) ? FIELD_TYPE_LONGLONG : + FIELD_TYPE_DOUBLE); } -void Item_avg_field::make_field(Send_field *tmp_field) +/* ARGSUSED */ +void Item_field::make_field(Send_field *tmp_field) { - init_make_field(tmp_field,FIELD_TYPE_DOUBLE); + field->make_field(tmp_field); + if (name) + tmp_field->col_name=name; // Use user supplied name } -void Item_std_field::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_DOUBLE); -} /* ** Set a field:s value from a item @@ -897,30 +852,109 @@ int Item_varbinary::save_in_field(Field *field, bool no_conversions) } -void Item_varbinary::make_field(Send_field *tmp_field) +/* + Pack data in buffer for sending +*/ + +bool Item_null::send(Protocol *protocol, String *packet) { - init_make_field(tmp_field,FIELD_TYPE_STRING); + return protocol->store_null(); } /* -** pack data in buffer for sending + This is only called from items that is not of type item_field */ -bool Item::send(THD *thd, String *packet) +bool Item::send(Protocol *protocol, String *buffer) { - char buff[MAX_FIELD_WIDTH]; - CONVERT *convert; - String s(buff,sizeof(buff),packet->charset()),*res; - if (!(res=val_str(&s))) - return net_store_null(packet); - if ((convert=thd->variables.convert_set)) - return convert->store(packet,res->ptr(),res->length()); - return net_store_data(packet,res->ptr(),res->length()); + bool result; + enum_field_types type; + LINT_INIT(result); + + switch ((type=field_type())) { + default: + DBUG_ASSERT(1); + /* If not assert on, send as a string */ + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + { + String *res; + if ((res=val_str(buffer))) + result= protocol->store(res->ptr(),res->length()); + break; + } + case MYSQL_TYPE_TINY: + { + longlong nr; + nr= val_int(); + if (!null_value) + result= protocol->store_tiny(nr); + break; + } + case MYSQL_TYPE_SHORT: + { + longlong nr; + nr= val_int(); + if (!null_value) + result= protocol->store_short(nr); + break; + } + case MYSQL_TYPE_LONG: + { + longlong nr; + nr= val_int(); + if (!null_value) + result= protocol->store_long(nr); + break; + } + case MYSQL_TYPE_LONGLONG: + { + longlong nr; + nr= val_int(); + if (!null_value) + result= protocol->store_longlong(nr, unsigned_flag); + break; + } + case MYSQL_TYPE_DOUBLE: + { + double nr; + nr= val(); + if (!null_value) + result= protocol->store(nr, decimals, buffer); + break; + } + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_DATE: + { + TIME tm; + get_date(&tm, 1); + if (!null_value) + { + if (type == MYSQL_TYPE_DATE) + return protocol->store_date(&tm); + else + result= protocol->store(&tm); + } + break; + } + case MYSQL_TYPE_TIME: + { + TIME tm; + get_time(&tm); + if (!null_value) + result= protocol->store_time(&tm); + break; + } + } + if (null_value) + result= protocol->store_null(); + return result; } -bool Item_null::send(THD *thd, String *packet) + +bool Item_field::send(Protocol *protocol, String *buffer) { - return net_store_null(packet); + return protocol->store(result_field); } /* diff --git a/sql/item.h b/sql/item.h index 4dff0591c09..63890ea3f64 100644 --- a/sql/item.h +++ b/sql/item.h @@ -19,6 +19,7 @@ #pragma interface /* gcc class implementation */ #endif +class Protocol; struct st_table_list; void item_init(void); /* Init item functions */ @@ -53,20 +54,21 @@ public: virtual ~Item() { name=0; } /*lint -e1509 */ void set_name(const char *str,uint length=0); void init_make_field(Send_field *tmp_field,enum enum_field_types type); + virtual void make_field(Send_field *field); virtual bool fix_fields(THD *, struct st_table_list *, Item **); virtual int save_in_field(Field *field, bool no_conversions); virtual void save_org_in_field(Field *field) { (void) save_in_field(field, 1); } virtual int save_safe_in_field(Field *field) { return save_in_field(field, 1); } - virtual bool send(THD *thd, String *str); + virtual bool send(Protocol *protocol, String *str); virtual bool eq(const Item *, bool binary_cmp) const; virtual Item_result result_type () const { return REAL_RESULT; } + virtual enum_field_types field_type() const; virtual enum Type type() const =0; virtual double val()=0; virtual longlong val_int()=0; virtual String *val_str(String*)=0; - virtual void make_field(Send_field *field)=0; virtual Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return 0; } virtual const char *full_name() const { return name ? name : "???"; } virtual double val_result() { return val(); } @@ -117,10 +119,10 @@ public: item (it assign '*ref' with field 'item' in derived classes) */ enum Type type() const { return item->type(); } + enum_field_types field_type() const { return item->field_type(); } double val() { return item->val(); } longlong val_int() { return item->val_int(); } String* val_str(String* s) { return item->val_str(s); } - void make_field(Send_field* f) { item->make_field(f); } bool check_cols(uint col) { return item->check_cols(col); } }; @@ -189,12 +191,9 @@ public: longlong val_int_result(); String *str_result(String* tmp); bool is_null_result() { return result_field->is_null(); } - bool send(THD *thd, String *str_arg) - { - return result_field->send(thd,str_arg); - } - void make_field(Send_field *field); + bool send(Protocol *protocol, String *str_arg); bool fix_fields(THD *, struct st_table_list *, Item **); + void make_field(Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); void save_org_in_field(Field *field); table_map used_tables() const; @@ -202,6 +201,10 @@ public: { return field->result_type(); } + enum_field_types field_type() + { + return field->type(); + } Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; } bool get_date(TIME *ltime,bool fuzzydate); bool get_time(TIME *ltime); @@ -219,12 +222,17 @@ public: double val(); longlong val_int(); String *val_str(String *str); - void make_field(Send_field *field); int save_in_field(Field *field, bool no_conversions); int save_safe_in_field(Field *field); - enum Item_result result_type () const - { return STRING_RESULT; } - bool send(THD *thd, String *str); + enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_NULL; } + bool fix_fields(THD *thd, struct st_table_list *list, Item **item) + { + bool res= Item::fix_fields(thd, list, item); + max_length=0; + return res; + } + bool send(Protocol *protocol, String *str); bool basic_const_item() const { return 1; } Item *new_item() { return new Item_null(name); } bool is_null() { return 1; } @@ -251,7 +259,6 @@ public: double val(); longlong val_int(); String *val_str(String*); - void make_field(Send_field *field); int save_in_field(Field *field, bool no_conversions); void set_null(); void set_int(longlong i); @@ -265,6 +272,7 @@ public: void (*setup_param_func)(Item_param *param, uchar **pos); enum Item_result result_type () const { return item_result_type; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } Item *new_item() { return new Item_param(name); } }; @@ -285,11 +293,11 @@ public: (longlong) strtoull(str_arg,(char**) 0,10)) { max_length= (uint) strlen(str_arg); name=(char*) str_arg;} enum Type type() const { return INT_ITEM; } - virtual enum Item_result result_type () const { return INT_RESULT; } + enum Item_result result_type () const { return INT_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } longlong val_int() { return value; } double val() { return (double) value; } String *val_str(String*); - void make_field(Send_field *field); int save_in_field(Field *field, bool no_conversions); bool basic_const_item() const { return 1; } Item *new_item() { return new Item_int(name,value,max_length); } @@ -305,8 +313,13 @@ public: Item_uint(uint32 i) :Item_int((longlong) i, 10) {} double val() { return ulonglong2double(value); } String *val_str(String*); - void make_field(Send_field *field); Item *new_item() { return new Item_uint(name,max_length); } + bool fix_fields(THD *thd, struct st_table_list *list, Item **item) + { + bool res= Item::fix_fields(thd, list, item); + unsigned_flag= 1; + return res; + } void print(String *str); }; @@ -332,10 +345,10 @@ public: Item_real(double value_par) :value(value_par) {} int save_in_field(Field *field, bool no_conversions); enum Type type() const { return REAL_ITEM; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } double val() { return value; } longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5));} String *val_str(String*); - void make_field(Send_field *field); bool basic_const_item() const { return 1; } Item *new_item() { return new Item_real(name,value,decimals,max_length); } }; @@ -380,8 +393,8 @@ public: } String *val_str(String*) { return (String*) &str_value; } int save_in_field(Field *field, bool no_conversions); - void make_field(Send_field *field); enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } bool basic_const_item() const { return 1; } bool eq(const Item *item, bool binary_cmp) const; Item *new_item() { return new Item_string(name,str_value.ptr(),max_length,default_charset_info); } @@ -398,7 +411,6 @@ class Item_default :public Item public: Item_default() { name= (char*) "DEFAULT"; } enum Type type() const { return DEFAULT_ITEM; } - void make_field(Send_field *field) {} int save_in_field(Field *field, bool no_conversions) { field->set_default(); @@ -418,7 +430,7 @@ class Item_datetime :public Item_string public: Item_datetime(const char *item_name): Item_string(item_name,"",0,default_charset_info) { max_length=19;} - void make_field(Send_field *field); + enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } }; class Item_empty_string :public Item_string @@ -428,6 +440,20 @@ public: { name=(char*) header; max_length=length;} }; +class Item_return_int :public Item_int +{ + enum_field_types int_field_type; +public: + Item_return_int(const char *name, uint length, + enum_field_types field_type_arg) + :Item_int(name, 0, length), int_field_type(field_type_arg) + { + unsigned_flag=1; + } + enum_field_types field_type() const { return int_field_type; } +}; + + class Item_varbinary :public Item { public: @@ -438,8 +464,8 @@ public: longlong val_int(); String *val_str(String*) { return &str_value; } int save_in_field(Field *field, bool no_conversions); - void make_field(Send_field *field); enum Item_result result_type () const { return INT_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } }; @@ -494,13 +520,14 @@ public: { return (null_value=(*ref)->get_date(ltime,fuzzydate)); } - bool send(THD *thd, String *tmp) { return (*ref)->send(thd, tmp); } + bool send(Protocol *prot, String *tmp){ return (*ref)->send(prot, tmp); } void make_field(Send_field *field) { (*ref)->make_field(field); } bool fix_fields(THD *, struct st_table_list *, Item **); int save_in_field(Field *field, bool no_conversions) { return (*ref)->save_in_field(field, no_conversions); } void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } + enum_field_types field_type() const { return (*ref)->field_type(); } table_map used_tables() const { return (*ref)->used_tables(); } bool check_loop(uint id); }; @@ -550,6 +577,7 @@ public: ~Item_copy_string() { delete item; } enum Type type() const { return COPY_STR_ITEM; } enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } double val() { return null_value ? 0.0 : my_strntod(str_value.charset(),str_value.ptr(),str_value.length(),NULL); } longlong val_int() diff --git a/sql/item_func.cc b/sql/item_func.cc index c84b554b522..1ce5b038f3b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1945,8 +1945,6 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { - if (!thd) - thd=current_thd; // Should never happen if (Item_func::fix_fields(thd, tables, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return 1; diff --git a/sql/item_func.h b/sql/item_func.h index 98e56af368c..5de493a5341 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -106,7 +106,6 @@ public: Item_func(List<Item> &list); ~Item_func() {} /* Nothing to do; Items are freed automaticly */ bool fix_fields(THD *,struct st_table_list *, Item **ref); - void make_field(Send_field *field); table_map used_tables() const; void update_used_tables(); bool eq(const Item *item, bool binary_cmp) const; @@ -909,7 +908,9 @@ class Item_func_set_user_var :public Item_func user_var_entry *entry; public: - Item_func_set_user_var(LEX_STRING a,Item *b): Item_func(b), name(a) {} + Item_func_set_user_var(LEX_STRING a,Item *b) + :Item_func(b), cached_result_type(INT_RESULT), name(a) + {} double val(); longlong val_int(); String *val_str(String *str); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index e087664e060..87a1bfcd952 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -73,20 +73,6 @@ void Item_subselect::select_transformer(st_select_lex *select_lex) } -void Item_subselect::make_field (Send_field *tmp_field) -{ - if (null_value) - { - init_make_field(tmp_field,FIELD_TYPE_NULL); - tmp_field->length=4; - } else { - init_make_field(tmp_field, ((result_type() == STRING_RESULT) ? - FIELD_TYPE_VAR_STRING : - (result_type() == INT_RESULT) ? - FIELD_TYPE_LONGLONG : FIELD_TYPE_DOUBLE)); - } -} - bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { if (substitution) diff --git a/sql/item_subselect.h b/sql/item_subselect.h index d323dab51f1..648a1885814 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -74,7 +74,6 @@ public: void assigned(bool a) { value_assigned= a; } enum Type type() const; bool is_null() { return null_value; } - void make_field (Send_field *); bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); virtual void fix_length_and_dec(); table_map used_tables() const; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index a1f772f4d46..6307c94ac4f 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -47,28 +47,21 @@ void Item_sum::mark_as_sum_func() with_sum_func= 1; } + void Item_sum::make_field(Send_field *tmp_field) { if (args[0]->type() == Item::FIELD_ITEM && keep_field_type()) - ((Item_field*) args[0])->field->make_field(tmp_field); - else { - tmp_field->flags=0; - if (!maybe_null) - tmp_field->flags|= NOT_NULL_FLAG; - if (unsigned_flag) - tmp_field->flags |= UNSIGNED_FLAG; - tmp_field->length=max_length; - tmp_field->decimals=decimals; - tmp_field->type=(result_type() == INT_RESULT ? FIELD_TYPE_LONG : - result_type() == REAL_RESULT ? FIELD_TYPE_DOUBLE : - FIELD_TYPE_VAR_STRING); + ((Item_field*) args[0])->field->make_field(tmp_field); + tmp_field->db_name=(char*)""; + tmp_field->org_table_name=tmp_field->table_name=(char*)""; + tmp_field->org_col_name=tmp_field->col_name=name; } - tmp_field->db_name=(char*)""; - tmp_field->org_table_name=tmp_field->table_name=(char*)""; - tmp_field->org_col_name=tmp_field->col_name=name; + else + init_make_field(tmp_field, field_type()); } + void Item_sum::print(String *str) { str->append(func_name()); @@ -170,6 +163,10 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) null_value=1; fix_length_and_dec(); thd->allow_sum_func=1; // Allow group functions + if (item->type() == Item::FIELD_ITEM) + hybrid_field_type= ((Item_field*) item)->field->type(); + else + hybrid_field_type= Item::field_type(); fixed= 1; return 0; } diff --git a/sql/item_sum.h b/sql/item_sum.h index 23b8482d41a..47c0b9284fc 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -210,7 +210,7 @@ public: longlong val_int() { return (longlong) val(); } bool is_null() { (void) val_int(); return null_value; } String *val_str(String*); - void make_field(Send_field *field); + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } void fix_length_and_dec() {} }; @@ -247,7 +247,7 @@ public: longlong val_int() { return (longlong) val(); } String *val_str(String*); bool is_null() { (void) val_int(); return null_value; } - void make_field(Send_field *field); + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } void fix_length_and_dec() {} }; @@ -281,6 +281,7 @@ class Item_sum_hybrid :public Item_sum double sum; longlong sum_int; Item_result hybrid_type; + enum_field_types hybrid_field_type; int cmp_sign; table_map used_table_cache; @@ -307,6 +308,7 @@ class Item_sum_hybrid :public Item_sum void make_const() { used_table_cache=0; } bool keep_field_type(void) const { return 1; } enum Item_result result_type () const { return hybrid_type; } + enum enum_field_types field_type() const { return hybrid_field_type; } void update_field(int offset); void min_max_update_str_field(int offset); void min_max_update_real_field(int offset); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 40397351c18..b4a0b517090 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -316,6 +316,7 @@ public: Item_date() :Item_func() {} Item_date(Item *a) :Item_func(a) {} enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_DATE; } String *val_str(String *str); double val() { return (double) val_int(); } const char *func_name() const { return "date"; } @@ -326,10 +327,6 @@ public: max_length=10*thd_charset()->mbmaxlen; } int save_in_field(Field *to, bool no_conversions); - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_DATE); - } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg, thd_charset()); @@ -343,10 +340,7 @@ public: Item_date_func() :Item_str_func() {} Item_date_func(Item *a) :Item_str_func(a) {} Item_date_func(Item *a,Item *b) :Item_str_func(a,b) {} - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_DATETIME); - } + enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : new Field_datetime(maybe_null, name, @@ -364,15 +358,12 @@ public: Item_func_curtime() :Item_func() {} Item_func_curtime(Item *a) :Item_func(a) {} enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_TIME; } double val() { return (double) value; } longlong val_int() { return value; } String *val_str(String *str); const char *func_name() const { return "curtime"; } void fix_length_and_dec(); - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_TIME); - } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : @@ -470,11 +461,8 @@ public: maybe_null=1; max_length=13*thd_charset()->mbmaxlen; } + enum_field_types field_type() const { return MYSQL_TYPE_TIME; } const char *func_name() const { return "sec_to_time"; } - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_TIME); - } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : @@ -566,10 +554,7 @@ class Item_date_typecast :public Item_typecast public: Item_date_typecast(Item *a) :Item_typecast(a) {} const char *func_name() const { return "date"; } - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_DATE); - } + enum_field_types field_type() const { return MYSQL_TYPE_DATE; } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : @@ -583,10 +568,7 @@ class Item_time_typecast :public Item_typecast public: Item_time_typecast(Item *a) :Item_typecast(a) {} const char *func_name() const { return "time"; } - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_TIME); - } + enum_field_types field_type() const { return MYSQL_TYPE_TIME; } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : @@ -600,10 +582,7 @@ class Item_datetime_typecast :public Item_typecast public: Item_datetime_typecast(Item *a) :Item_typecast(a) {} const char *func_name() const { return "datetime"; } - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_DATETIME); - } + enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : new Field_datetime(maybe_null, name, diff --git a/sql/log_event.cc b/sql/log_event.cc index 5050bba9965..1f4371d5919 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -306,9 +306,9 @@ int Log_event::exec_event(struct st_relay_log_info* rli) Log_event::pack_info() ****************************************************************************/ -void Log_event::pack_info(String* packet) +void Log_event::pack_info(Protocol *protocol) { - net_store_data(packet, "", 0); + protocol->store("",0); } /***************************************************************************** @@ -319,10 +319,13 @@ void Log_event::pack_info(String* packet) void Log_event::init_show_field_list(List<Item>* field_list) { field_list->push_back(new Item_empty_string("Log_name", 20)); - field_list->push_back(new Item_empty_string("Pos", 20)); + field_list->push_back(new Item_return_int("Pos", 11, + MYSQL_TYPE_LONGLONG)); field_list->push_back(new Item_empty_string("Event_type", 20)); - field_list->push_back(new Item_empty_string("Server_id", 20)); - field_list->push_back(new Item_empty_string("Orig_log_pos", 20)); + field_list->push_back(new Item_return_int("Server_id", 10, + MYSQL_TYPE_LONG)); + field_list->push_back(new Item_return_int("Orig_log_pos", 11, + MYSQL_TYPE_LONGLONG)); field_list->push_back(new Item_empty_string("Info", 20)); } @@ -333,23 +336,22 @@ void Log_event::init_show_field_list(List<Item>* field_list) Only called by SHOW BINLOG EVENTS ****************************************************************************/ -int Log_event::net_send(THD* thd_arg, const char* log_name, my_off_t pos) +int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos) { - String* packet = &thd_arg->packet; const char *p= strrchr(log_name, FN_LIBCHAR); const char *event_type; if (p) log_name = p + 1; - packet->length(0); - net_store_data(packet, log_name, strlen(log_name)); - net_store_data(packet, (longlong) pos); + protocol->prepare_for_resend(); + protocol->store(log_name); + protocol->store((ulonglong) pos); event_type = get_type_str(); - net_store_data(packet, event_type, strlen(event_type)); - net_store_data(packet, server_id); - net_store_data(packet, (longlong) log_pos); - pack_info(packet); - return my_net_write(&thd_arg->net, (char*) packet->ptr(), packet->length()); + protocol->store(event_type, strlen(event_type)); + protocol->store((uint32) server_id); + protocol->store((ulonglong) log_pos); + pack_info(protocol); + return protocol->write(); } #endif // !MYSQL_CLIENT @@ -671,7 +673,7 @@ void Log_event::set_log_pos(MYSQL_LOG* log) Query_log_event::pack_info() ****************************************************************************/ -void Query_log_event::pack_info(String* packet) +void Query_log_event::pack_info(Protocol *protocol) { char buf[256]; String tmp(buf, sizeof(buf), system_charset_info); @@ -685,7 +687,7 @@ void Query_log_event::pack_info(String* packet) if (query && q_len) tmp.append(query, q_len); - net_store_data(packet, (char*)tmp.ptr(), tmp.length()); + protocol->store((char*) tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -925,7 +927,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) ****************************************************************************/ #ifndef MYSQL_CLIENT -void Start_log_event::pack_info(String* packet) +void Start_log_event::pack_info(Protocol *protocol) { char buf1[256]; String tmp(buf1, sizeof(buf1), system_charset_info); @@ -936,7 +938,7 @@ void Start_log_event::pack_info(String* packet) tmp.append(server_version); tmp.append(", Binlog ver: "); tmp.append(llstr(binlog_version, buf)); - net_store_data(packet, tmp.ptr(), tmp.length()); + protocol->store(tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -1036,7 +1038,7 @@ int Start_log_event::exec_event(struct st_relay_log_info* rli) ****************************************************************************/ #ifndef MYSQL_CLIENT -void Load_log_event::pack_info(String* packet) +void Load_log_event::pack_info(Protocol *protocol) { char buf[256]; String tmp(buf, sizeof(buf), system_charset_info); @@ -1109,7 +1111,7 @@ void Load_log_event::pack_info(String* packet) tmp.append(')'); } - net_store_data(packet, tmp.ptr(), tmp.length()); + protocol->store(tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -1542,7 +1544,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) ****************************************************************************/ #ifndef MYSQL_CLIENT -void Rotate_log_event::pack_info(String* packet) +void Rotate_log_event::pack_info(Protocol *protocol) { char buf1[256], buf[22]; String tmp(buf1, sizeof(buf1), system_charset_info); @@ -1552,7 +1554,7 @@ void Rotate_log_event::pack_info(String* packet) tmp.append(llstr(pos,buf)); if (flags & LOG_EVENT_FORCED_ROTATE_F) tmp.append("; forced by master"); - net_store_data(packet, tmp.ptr(), tmp.length()); + protocol->store(tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -1680,7 +1682,7 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) ****************************************************************************/ #ifndef MYSQL_CLIENT -void Intvar_log_event::pack_info(String* packet) +void Intvar_log_event::pack_info(Protocol *protocol) { char buf1[256], buf[22]; String tmp(buf1, sizeof(buf1), system_charset_info); @@ -1688,7 +1690,7 @@ void Intvar_log_event::pack_info(String* packet) tmp.append(get_var_type_name()); tmp.append('='); tmp.append(llstr(val, buf)); - net_store_data(packet, tmp.ptr(), tmp.length()); + protocol->store(tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -1801,14 +1803,14 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli) ****************************************************************************/ #ifndef MYSQL_CLIENT -void Rand_log_event::pack_info(String* packet) +void Rand_log_event::pack_info(Protocol *protocol) { char buf1[256], *pos; pos= strmov(buf1,"rand_seed1="); pos= int10_to_str((long) seed1, pos, 10); pos= strmov(pos, ",rand_seed2="); pos= int10_to_str((long) seed2, pos, 10); - net_store_data(packet, buf1, (uint) (pos-buf1)); + protocol->store(buf1, (uint) (pos-buf1)); } #endif // !MYSQL_CLIENT @@ -1888,7 +1890,7 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli) ****************************************************************************/ #ifndef MYSQL_CLIENT -void Slave_log_event::pack_info(String* packet) +void Slave_log_event::pack_info(Protocol *protocol) { char buf1[256], buf[22], *end; String tmp(buf1, sizeof(buf1), system_charset_info); @@ -1902,7 +1904,7 @@ void Slave_log_event::pack_info(String* packet) tmp.append(master_log); tmp.append(",pos="); tmp.append(llstr(master_pos,buf)); - net_store_data(packet, tmp.ptr(), tmp.length()); + protocol->store(tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -2236,7 +2238,7 @@ void Create_file_log_event::print(FILE* file, bool short_form, ****************************************************************************/ #ifndef MYSQL_CLIENT -void Create_file_log_event::pack_info(String* packet) +void Create_file_log_event::pack_info(Protocol *protocol) { char buf1[256],buf[22], *end; String tmp(buf1, sizeof(buf1), system_charset_info); @@ -2251,7 +2253,7 @@ void Create_file_log_event::pack_info(String* packet) tmp.append(";block_len="); end= int10_to_str((long) block_len, buf, 10); tmp.append(buf, (uint32) (end-buf)); - net_store_data(packet, (char*) tmp.ptr(), tmp.length()); + protocol->store((char*) tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -2395,14 +2397,14 @@ void Append_block_log_event::print(FILE* file, bool short_form, ****************************************************************************/ #ifndef MYSQL_CLIENT -void Append_block_log_event::pack_info(String* packet) +void Append_block_log_event::pack_info(Protocol *protocol) { char buf[256]; uint length; length= (uint) my_sprintf(buf, (buf, ";file_id=%u;block_len=%u", file_id, block_len)); - net_store_data(packet, buf, (int32) length); + protocol->store(buf, (int32) length); } #endif // !MYSQL_CLIENT @@ -2510,12 +2512,12 @@ void Delete_file_log_event::print(FILE* file, bool short_form, ****************************************************************************/ #ifndef MYSQL_CLIENT -void Delete_file_log_event::pack_info(String* packet) +void Delete_file_log_event::pack_info(Protocol *protocol) { char buf[64]; uint length; length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id)); - net_store_data(packet, buf, (int32) length); + protocol->store(buf, (int32) length); } #endif // !MYSQL_CLIENT @@ -2609,12 +2611,12 @@ void Execute_load_log_event::print(FILE* file, bool short_form, ****************************************************************************/ #ifndef MYSQL_CLIENT -void Execute_load_log_event::pack_info(String* packet) +void Execute_load_log_event::pack_info(Protocol *protocol) { char buf[64]; uint length; length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id)); - net_store_data(packet, buf, (int32) length); + protocol->store(buf, (int32) length); } #endif // !MYSQL_CLIENT diff --git a/sql/log_event.h b/sql/log_event.h index 20a134ab3cc..c4f93c7a9b6 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -267,8 +267,8 @@ public: static int read_log_event(IO_CACHE* file, String* packet, pthread_mutex_t* log_lock); void set_log_pos(MYSQL_LOG* log); - virtual void pack_info(String* packet); - int net_send(THD* thd, const char* log_name, my_off_t pos); + virtual void pack_info(Protocol *protocol); + int net_send(Protocol *protocol, const char* log_name, my_off_t pos); static void init_show_field_list(List<Item>* field_list); virtual int exec_event(struct st_relay_log_info* rli); virtual const char* get_db() @@ -355,7 +355,7 @@ public: Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans); const char* get_db() { return db; } - void pack_info(String* packet); + 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); @@ -404,7 +404,7 @@ public: #ifndef MYSQL_CLIENT Slave_log_event(THD* thd_arg, struct st_relay_log_info* rli); - void pack_info(String* packet); + 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); @@ -454,7 +454,7 @@ public: List<Item>& fields_arg, enum enum_duplicates handle_dup, bool using_trans); void set_fields(List<Item> &fields_arg); - void pack_info(String* packet); + void pack_info(Protocol* protocol); const char* get_db() { return db; } int exec_event(struct st_relay_log_info* rli) { @@ -507,7 +507,7 @@ public: created = (uint32) when; memcpy(server_version, ::server_version, ST_SERVER_VER_LEN); } - void pack_info(String* packet); + 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); @@ -542,7 +542,7 @@ public: Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg) :Log_event(),val(val_arg),type(type_arg) {} - void pack_info(String* packet); + 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); @@ -574,7 +574,7 @@ class Rand_log_event: public Log_event Rand_log_event(THD* thd_arg, ulonglong seed1_arg, ulonglong seed2_arg) :Log_event(thd_arg,0,0),seed1(seed1_arg),seed2(seed2_arg) {} - void pack_info(String* packet); + 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); @@ -636,7 +636,7 @@ public: pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg : (uint) strlen(new_log_ident_arg)), alloced(0) {} - void pack_info(String* packet); + 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); @@ -683,7 +683,7 @@ public: enum enum_duplicates handle_dup, char* block_arg, uint block_len_arg, bool using_trans); - void pack_info(String* packet); + 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); @@ -734,7 +734,7 @@ public: Append_block_log_event(THD* thd, char* block_arg, uint block_len_arg, bool using_trans); int exec_event(struct st_relay_log_info* rli); - void pack_info(String* packet); + void pack_info(Protocol* protocol); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); #endif @@ -759,7 +759,7 @@ public: #ifndef MYSQL_CLIENT Delete_file_log_event(THD* thd, bool using_trans); - void pack_info(String* packet); + 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); @@ -785,7 +785,7 @@ public: #ifndef MYSQL_CLIENT Execute_load_log_event(THD* thd, bool using_trans); - void pack_info(String* packet); + 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); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 771d105a1c7..e3ebf14dcbe 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -283,6 +283,7 @@ inline THD *_current_thd(void) #include "handler.h" #include "table.h" #include "field.h" /* Field definitions */ +#include "protocol.h" #include "sql_udf.h" #include "item.h" typedef compare_func_creator (*chooser_compare_func_creator)(bool invert); @@ -377,30 +378,6 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* table_list, HA_CHECK_OPT* check_opt); bool check_simple_select(); -/* net_pkg.c */ -void send_warning(THD *thd, uint sql_errno, const char *err=0); -void net_printf(THD *thd,uint sql_errno, ...); -void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, - const char *info=0); -void send_eof(THD *thd, bool no_flush=0); -void net_send_error(NET *net, uint sql_errno, const char *err); -char *net_store_length(char *packet,ulonglong length); -char *net_store_length(char *packet,uint length); -char *net_store_data(char *to,const char *from); -char *net_store_data(char *to,int32 from); -char *net_store_data(char *to,longlong from); - -bool net_store_null(String *packet); -bool net_store_data(String *packet,uint32 from); -bool net_store_data(String *packet,longlong from); -bool net_store_data(String *packet,const char *from); -bool net_store_data(String *packet,const char *from,uint length); -bool net_store_data(String *packet,struct tm *tmp); -bool net_store_data(String* packet, I_List<i_string>* str_list); -bool net_store_data(String *packet,CONVERT *convert, const char *from, - uint length); -bool net_store_data(String *packet, CONVERT *convert, const char *from); - SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length); int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields, List <Item> &all_fields, ORDER *order); @@ -594,7 +571,6 @@ int lock_tables(THD *thd,TABLE_LIST *tables); TABLE *open_temporary_table(THD *thd, const char *path, const char *db, const char *table_name, bool link_in_list); bool rm_temporary_table(enum db_type base, char *path); -bool send_fields(THD *thd,List<Item> &item,uint send_field_count); void free_io_cache(TABLE *entry); void intern_close_table(TABLE *entry); bool close_thread_table(THD *thd, TABLE **table_ptr); @@ -818,6 +794,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time); longlong str_to_datetime(const char *str,uint length,bool fuzzy_date); timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time, bool fuzzy_date); +void localtime_to_TIME(TIME *to, struct tm *from); int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(byte *,uint,char,char); diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc deleted file mode 100644 index 1da625e776f..00000000000 --- a/sql/net_pkg.cc +++ /dev/null @@ -1,492 +0,0 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - - -#include "mysql_priv.h" -#include <stdarg.h> - - /* Send a error string to client */ - -void send_error(THD *thd, uint sql_errno, const char *err) -{ - uint length; - char buff[MYSQL_ERRMSG_SIZE+2]; - NET *net= &thd->net; - DBUG_ENTER("send_error"); - DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, - err ? err : net->last_error[0] ? - net->last_error : "NULL")); - - query_cache_abort(net); - thd->query_error= 1; // needed to catch query errors during replication - if (!err) - { - if (sql_errno) - err=ER(sql_errno); - else - { - if ((err=net->last_error)[0]) - sql_errno=net->last_errno; - else - { - sql_errno=ER_UNKNOWN_ERROR; - err=ER(sql_errno); /* purecov: inspected */ - } - } - } - if (net->vio == 0) - { - if (thd->bootstrap) - { - /* In bootstrap it's ok to print on stderr */ - fprintf(stderr,"ERROR: %d %s\n",sql_errno,err); - } - DBUG_VOID_RETURN; - } - - if (net->return_errno) - { // new client code; Add errno before message - int2store(buff,sql_errno); - length= (uint) (strmake(buff+2,err,MYSQL_ERRMSG_SIZE-1) - buff); - err=buff; - } - else - { - length=(uint) strlen(err); - set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); - } - VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length)); - thd->fatal_error=0; // Error message is given - thd->net.report_error= 0; - DBUG_VOID_RETURN; -} - -/* - Send an error to the client when a connection is forced close - This is used by mysqld.cc, which doesn't have a THD -*/ - -void net_send_error(NET *net, uint sql_errno, const char *err) -{ - char buff[2]; - uint length; - DBUG_ENTER("send_net_error"); - - int2store(buff,sql_errno); - length=(uint) strlen(err); - set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); - net_write_command(net,(uchar) 255, buff, 2, err, length); - DBUG_VOID_RETURN; -} - - -/* - Send a warning to the end user - - SYNOPSIS - send_warning() - thd Thread handler - sql_errno Warning number (error message) - err Error string. If not set, use ER(sql_errno) - - DESCRIPTION - Register the warning so that the user can get it with mysql_warnings() - Send an ok (+ warning count) to the end user. -*/ - -void send_warning(THD *thd, uint sql_errno, const char *err) -{ - DBUG_ENTER("send_warning"); - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno, - err ? err : ER(sql_errno)); - send_ok(thd); - DBUG_VOID_RETURN; -} - - -/* - Write error package and flush to client - It's a little too low level, but I don't want to use another buffer for - this -*/ - -void -net_printf(THD *thd, uint errcode, ...) -{ - va_list args; - uint length,offset; - const char *format,*text_pos; - int head_length= NET_HEADER_SIZE; - NET *net= &thd->net; - DBUG_ENTER("net_printf"); - DBUG_PRINT("enter",("message: %u",errcode)); - - thd->query_error= 1; // needed to catch query errors during replication - query_cache_abort(net); // Safety - va_start(args,errcode); - /* - The following is needed to make net_printf() work with 0 argument for - errorcode and use the argument after that as the format string. This - is useful for rare errors that are not worth the hassle to put in - errmsg.sys, but at the same time, the message is not fixed text - */ - if (errcode) - format= ER(errcode); - else - { - format=va_arg(args,char*); - errcode= ER_UNKNOWN_ERROR; - } - offset= net->return_errno ? 2 : 0; - text_pos=(char*) net->buff+head_length+offset+1; - (void) vsprintf(my_const_cast(char*) (text_pos),format,args); - length=(uint) strlen((char*) text_pos); - if (length >= sizeof(net->last_error)) - length=sizeof(net->last_error)-1; /* purecov: inspected */ - va_end(args); - - if (net->vio == 0) - { - if (thd->bootstrap) - { - /* In bootstrap it's ok to print on stderr */ - fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos); - thd->fatal_error=1; - } - DBUG_VOID_RETURN; - } - - int3store(net->buff,length+1+offset); - net->buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); - net->buff[head_length]=(uchar) 255; // Error package - if (offset) - int2store(text_pos-2, errcode); - VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset)); - thd->fatal_error=0; // Error message is given - DBUG_VOID_RETURN; -} - - -/* - Return ok to the client. - - SYNOPSIS - send_ok() - thd Thread handler - affected_rows Number of rows changed by statement - id Auto_increment id for first row (if used) - message Message to send to the client (Used by mysql_status) - - DESCRIPTION - The ok packet has the following structure - - 0 Marker (1 byte) - affected_rows Stored in 1-9 bytes - id Stored in 1-9 bytes - server_status Copy of thd->server_status; Can be used by client - to check if we are inside an transaction - New in 4.0 protocol - warning_count Stored in 2 bytes; New in 4.1 protocol - message Stored as packed length (1-9 bytes) + message - Is not stored if no message - - If net->no_send_ok return without sending packet -*/ - -void -send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) -{ - NET *net= &thd->net; - if (net->no_send_ok || !net->vio) // hack for re-parsing queries - return; - - char buff[MYSQL_ERRMSG_SIZE+10],*pos; - DBUG_ENTER("send_ok"); - buff[0]=0; // No fields - pos=net_store_length(buff+1,(ulonglong) affected_rows); - pos=net_store_length(pos, (ulonglong) id); - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - int2store(pos,thd->server_status); - pos+=2; - - /* We can only return up to 65535 warnings in two bytes */ - uint tmp= min(thd->total_warn_count, 65535); - int2store(pos, tmp); - pos+= 2; - } - else if (net->return_status) // For 4.0 protocol - { - int2store(pos,thd->server_status); - pos+=2; - } - if (message) - pos=net_store_data((char*) pos,message); - VOID(my_net_write(net,buff,(uint) (pos-buff))); - VOID(net_flush(net)); - DBUG_VOID_RETURN; -} - - -/* - Send eof (= end of result set) to the client - - SYNOPSIS - send_eof() - thd Thread handler - no_flush Set to 1 if there will be more data to the client, - like in send_fields(). - - DESCRIPTION - The eof packet has the following structure - - 254 Marker (1 byte) - warning_count Stored in 2 bytes; New in 4.1 protocol - status_flag Stored in 2 bytes; - For flags like SERVER_STATUS_MORE_RESULTS - - Note that the warning count will not be sent if 'no_flush' is set as - we don't want to report the warning count until all data is sent to the - client. -*/ - -void -send_eof(THD *thd, bool no_flush) -{ - static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ - NET *net= &thd->net; - DBUG_ENTER("send_eof"); - if (net->vio != 0) - { - if (!no_flush && (thd->client_capabilities & CLIENT_PROTOCOL_41)) - { - uchar buff[5]; - uint tmp= min(thd->total_warn_count, 65535); - buff[0]=254; - int2store(buff+1, tmp); - int2store(buff+3, 0); // No flags yet - VOID(my_net_write(net,(char*) buff,5)); - VOID(net_flush(net)); - } - else - { - VOID(my_net_write(net,eof_buff,1)); - if (!no_flush) - VOID(net_flush(net)); - } - } - DBUG_VOID_RETURN; -} - - -/**************************************************************************** -** Store a field length in logical packet -****************************************************************************/ - -char * -net_store_length(char *pkg, ulonglong length) -{ - uchar *packet=(uchar*) pkg; - if (length < LL(251)) - { - *packet=(uchar) length; - return (char*) packet+1; - } - /* 251 is reserved for NULL */ - if (length < LL(65536)) - { - *packet++=252; - int2store(packet,(uint) length); - return (char*) packet+2; - } - if (length < LL(16777216)) - { - *packet++=253; - int3store(packet,(ulong) length); - return (char*) packet+3; - } - *packet++=254; - int8store(packet,length); - return (char*) packet+9; -} - -char * -net_store_length(char *pkg, uint length) -{ - uchar *packet=(uchar*) pkg; - if (length < 251) - { - *packet=(uchar) length; - return (char*) packet+1; - } - *packet++=252; - int2store(packet,(uint) length); - return (char*) packet+2; -} - -/* The following will only be used for short strings < 65K */ -char * -net_store_data(char *to,const char *from) -{ - uint length=(uint) strlen(from); - to=net_store_length(to,length); - memcpy(to,from,length); - return to+length; -} - - -char * -net_store_data(char *to,int32 from) -{ - char buff[20]; - uint length=(uint) (int10_to_str(from,buff,10)-buff); - to=net_store_length(to,length); - memcpy(to,buff,length); - return to+length; -} - -char * -net_store_data(char *to,longlong from) -{ - char buff[22]; - uint length=(uint) (longlong10_to_str(from,buff,10)-buff); - to=net_store_length(to,length); - memcpy(to,buff,length); - return to+length; -} - - -bool net_store_null(String *packet) -{ - return packet->append((char) 251); -} - -bool -net_store_data(String *packet,const char *from,uint length) -{ - ulong packet_length=packet->length(); - if (packet_length+5+length > packet->alloced_length() && - packet->realloc(packet_length+5+length)) - return 1; - char *to=(char*) net_store_length((char*) packet->ptr()+packet_length, - (ulonglong) length); - memcpy(to,from,length); - packet->length((uint) (to+length-packet->ptr())); - return 0; -} - -/* The following is only used at short, null terminated data */ - -bool -net_store_data(String *packet,const char *from) -{ - uint length=(uint) strlen(from); - uint packet_length=packet->length(); - if (packet_length+5+length > packet->alloced_length() && - packet->realloc(packet_length+5+length)) - return 1; - char *to=(char*) net_store_length((char*) packet->ptr()+packet_length, - length); - memcpy(to,from,length); - packet->length((uint) (to+length-packet->ptr())); - return 0; -} - - -bool -net_store_data(String *packet,uint32 from) -{ - char buff[20]; - return net_store_data(packet,(char*) buff, - (uint) (int10_to_str(from,buff,10)-buff)); -} - -bool -net_store_data(String *packet, longlong from) -{ - char buff[22]; - return net_store_data(packet,(char*) buff, - (uint) (longlong10_to_str(from,buff,10)-buff)); -} - -bool -net_store_data(String *packet,struct tm *tmp) -{ - char buff[20]; - sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d", - ((int) (tmp->tm_year+1900)) % 10000, - (int) tmp->tm_mon+1, - (int) tmp->tm_mday, - (int) tmp->tm_hour, - (int) tmp->tm_min, - (int) tmp->tm_sec); - return net_store_data(packet,(char*) buff,19); -} - -bool net_store_data(String* packet, I_List<i_string>* str_list) -{ - char buf[256]; - String tmp(buf, sizeof(buf), default_charset_info); - tmp.length(0); - I_List_iterator<i_string> it(*str_list); - i_string* s; - - while ((s=it++)) - { - if (tmp.length()) - tmp.append(','); - tmp.append(s->ptr); - } - - return net_store_data(packet, (char*)tmp.ptr(), tmp.length()); -} - -/* -** translate and store data; These are mainly used by the SHOW functions -*/ - -bool -net_store_data(String *packet,CONVERT *convert, const char *from,uint length) -{ - if (convert) - return convert->store(packet, from, length); - return net_store_data(packet,from,length); -} - -bool -net_store_data(String *packet, CONVERT *convert, const char *from) -{ - uint length=(uint) strlen(from); - if (convert) - return convert->store(packet, from, length); - return net_store_data(packet,from,length); -} - -/* - Function called by my_net_init() to set some check variables -*/ - -extern "C" { -void my_net_local_init(NET *net) -{ - net->max_packet= (uint) global_system_variables.net_buffer_length; - net->read_timeout= (uint) global_system_variables.net_read_timeout; - net->write_timeout=(uint) global_system_variables.net_write_timeout; - net->retry_count= (uint) global_system_variables.net_retry_count; - net->max_packet_size= max(global_system_variables.net_buffer_length, - global_system_variables.max_allowed_packet); -} -} diff --git a/sql/opt_range.cc b/sql/opt_range.cc index d76737e8e31..bcea522cb6d 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1042,7 +1042,8 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, DBUG_RETURN(0); if (maybe_null) *str= (char) field->is_real_null(); // Set to 1 if null - field->get_key_image(str+maybe_null,key_part->part_length, key_part->image_type); + field->get_key_image(str+maybe_null,key_part->part_length, + key_part->image_type); if (!(tree=new SEL_ARG(field,str,str))) DBUG_RETURN(0); @@ -2284,9 +2285,11 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key, key_tree->min_flag : key_tree->min_flag | key_tree->max_flag; } - /* Ensure that some part of min_key and max_key are used. If not, - regard this as no lower/upper range */ - if((flag & GEOM_FLAG) == 0) + /* + Ensure that some part of min_key and max_key are used. If not, + regard this as no lower/upper range + */ + if ((flag & GEOM_FLAG) == 0) { if (tmp_min_key != param->min_key) flag&= ~NO_MIN_RANGE; @@ -2451,17 +2454,17 @@ int QUICK_SELECT::get_next() if (!(range=it++)) DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used - if(range->flag & GEOM_FLAG) + if (range->flag & GEOM_FLAG) { if ((result = file->index_read(record, - (byte*) (range->min_key + ((range->flag & GEOM_FLAG) > 0)), - range->min_length, - (ha_rkey_function)(range->flag ^ GEOM_FLAG)))) - + (byte*) (range->min_key +1), + range->min_length, + (ha_rkey_function)(range->flag ^ + GEOM_FLAG)))) { if (result != HA_ERR_KEY_NOT_FOUND) DBUG_RETURN(result); - range=0; // Not found, to next range + range=0; // Not found, to next range continue; } DBUG_RETURN(0); @@ -2478,13 +2481,14 @@ int QUICK_SELECT::get_next() continue; } if ((result = file->index_read(record, - (byte*) (range->min_key + ((range->flag & GEOM_FLAG) > 0)), - range->min_length, - (range->flag & NEAR_MIN) ? - HA_READ_AFTER_KEY: - (range->flag & EQ_RANGE) ? - HA_READ_KEY_EXACT : - HA_READ_KEY_OR_NEXT))) + (byte*) (range->min_key + + test(range->flag & GEOM_FLAG)), + range->min_length, + (range->flag & NEAR_MIN) ? + HA_READ_AFTER_KEY: + (range->flag & EQ_RANGE) ? + HA_READ_KEY_EXACT : + HA_READ_KEY_OR_NEXT))) { if (result != HA_ERR_KEY_NOT_FOUND) @@ -2502,8 +2506,11 @@ int QUICK_SELECT::get_next() } } - /* compare if found key is over max-value */ - /* Returns 0 if key <= range->max_key */ + +/* + Compare if found key is over max-value + Returns 0 if key <= range->max_key +*/ int QUICK_SELECT::cmp_next(QUICK_RANGE *range_arg) { diff --git a/sql/procedure.h b/sql/procedure.h index b72c5cb559f..bc1b6062e1d 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -55,7 +55,7 @@ public: decimals=dec; max_length=float_length(dec); } enum Item_result result_type () const { return REAL_RESULT; } - enum_field_types field_type() const { return FIELD_TYPE_DOUBLE; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } void set(double nr) { value=nr; } void set(longlong nr) { value=(double) nr; } void set(const char *str,uint length,CHARSET_INFO *cs) @@ -73,7 +73,7 @@ public: Item_proc_int(const char *name_par) :Item_proc(name_par) { max_length=11; } enum Item_result result_type () const { return INT_RESULT; } - enum_field_types field_type() const { return FIELD_TYPE_LONG; } + enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } void set(double nr) { value=(longlong) nr; } void set(longlong nr) { value=nr; } void set(const char *str,uint length, CHARSET_INFO *cs) @@ -91,7 +91,7 @@ public: Item_proc_string(const char *name_par,uint length) :Item_proc(name_par) { this->max_length=length; } enum Item_result result_type () const { return STRING_RESULT; } - enum_field_types field_type() const { return FIELD_TYPE_STRING; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } void set(double nr) { str_value.set(nr, 2, thd_charset()); } void set(longlong nr) { str_value.set(nr, thd_charset()); } void set(const char *str, uint length, CHARSET_INFO *cs) diff --git a/sql/protocol.cc b/sql/protocol.cc new file mode 100644 index 00000000000..a7540f39f9e --- /dev/null +++ b/sql/protocol.cc @@ -0,0 +1,983 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Low level functions for storing data to be send to the MySQL client + The actual communction is handled by the net_xxx functions in net_serv.cc +*/ + +#ifdef __GNUC__ +#pragma implementation // gcc: Class implementation +#endif + +#include "mysql_priv.h" +#include <stdarg.h> +#include <assert.h> + + /* Send a error string to client */ + +void send_error(THD *thd, uint sql_errno, const char *err) +{ + uint length; + char buff[MYSQL_ERRMSG_SIZE+2]; + NET *net= &thd->net; + DBUG_ENTER("send_error"); + DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, + err ? err : net->last_error[0] ? + net->last_error : "NULL")); + + query_cache_abort(net); + thd->query_error= 1; // needed to catch query errors during replication + if (!err) + { + if (sql_errno) + err=ER(sql_errno); + else + { + if ((err=net->last_error)[0]) + sql_errno=net->last_errno; + else + { + sql_errno=ER_UNKNOWN_ERROR; + err=ER(sql_errno); /* purecov: inspected */ + } + } + } + if (net->vio == 0) + { + if (thd->bootstrap) + { + /* In bootstrap it's ok to print on stderr */ + fprintf(stderr,"ERROR: %d %s\n",sql_errno,err); + } + DBUG_VOID_RETURN; + } + + if (net->return_errno) + { // new client code; Add errno before message + int2store(buff,sql_errno); + length= (uint) (strmake(buff+2,err,MYSQL_ERRMSG_SIZE-1) - buff); + err=buff; + } + else + { + length=(uint) strlen(err); + set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); + } + VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length)); + thd->fatal_error=0; // Error message is given + thd->net.report_error= 0; + DBUG_VOID_RETURN; +} + +/* + Send an error to the client when a connection is forced close + This is used by mysqld.cc, which doesn't have a THD +*/ + +void net_send_error(NET *net, uint sql_errno, const char *err) +{ + char buff[2]; + uint length; + DBUG_ENTER("send_net_error"); + + int2store(buff,sql_errno); + length=(uint) strlen(err); + set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); + net_write_command(net,(uchar) 255, buff, 2, err, length); + DBUG_VOID_RETURN; +} + + +/* + Send a warning to the end user + + SYNOPSIS + send_warning() + thd Thread handler + sql_errno Warning number (error message) + err Error string. If not set, use ER(sql_errno) + + DESCRIPTION + Register the warning so that the user can get it with mysql_warnings() + Send an ok (+ warning count) to the end user. +*/ + +void send_warning(THD *thd, uint sql_errno, const char *err) +{ + DBUG_ENTER("send_warning"); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno, + err ? err : ER(sql_errno)); + send_ok(thd); + DBUG_VOID_RETURN; +} + + +/* + Write error package and flush to client + It's a little too low level, but I don't want to use another buffer for + this +*/ + +void +net_printf(THD *thd, uint errcode, ...) +{ + va_list args; + uint length,offset; + const char *format,*text_pos; + int head_length= NET_HEADER_SIZE; + NET *net= &thd->net; + DBUG_ENTER("net_printf"); + DBUG_PRINT("enter",("message: %u",errcode)); + + thd->query_error= 1; // needed to catch query errors during replication + query_cache_abort(net); // Safety + va_start(args,errcode); + /* + The following is needed to make net_printf() work with 0 argument for + errorcode and use the argument after that as the format string. This + is useful for rare errors that are not worth the hassle to put in + errmsg.sys, but at the same time, the message is not fixed text + */ + if (errcode) + format= ER(errcode); + else + { + format=va_arg(args,char*); + errcode= ER_UNKNOWN_ERROR; + } + offset= net->return_errno ? 2 : 0; + text_pos=(char*) net->buff+head_length+offset+1; + (void) vsprintf(my_const_cast(char*) (text_pos),format,args); + length=(uint) strlen((char*) text_pos); + if (length >= sizeof(net->last_error)) + length=sizeof(net->last_error)-1; /* purecov: inspected */ + va_end(args); + + if (net->vio == 0) + { + if (thd->bootstrap) + { + /* In bootstrap it's ok to print on stderr */ + fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos); + thd->fatal_error=1; + } + DBUG_VOID_RETURN; + } + + int3store(net->buff,length+1+offset); + net->buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); + net->buff[head_length]=(uchar) 255; // Error package + if (offset) + int2store(text_pos-2, errcode); + VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset)); + thd->fatal_error=0; // Error message is given + DBUG_VOID_RETURN; +} + + +/* + Return ok to the client. + + SYNOPSIS + send_ok() + thd Thread handler + affected_rows Number of rows changed by statement + id Auto_increment id for first row (if used) + message Message to send to the client (Used by mysql_status) + + DESCRIPTION + The ok packet has the following structure + + 0 Marker (1 byte) + affected_rows Stored in 1-9 bytes + id Stored in 1-9 bytes + server_status Copy of thd->server_status; Can be used by client + to check if we are inside an transaction + New in 4.0 protocol + warning_count Stored in 2 bytes; New in 4.1 protocol + message Stored as packed length (1-9 bytes) + message + Is not stored if no message + + If net->no_send_ok return without sending packet +*/ + +void +send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) +{ + NET *net= &thd->net; + if (net->no_send_ok || !net->vio) // hack for re-parsing queries + return; + + char buff[MYSQL_ERRMSG_SIZE+10],*pos; + DBUG_ENTER("send_ok"); + buff[0]=0; // No fields + pos=net_store_length(buff+1,(ulonglong) affected_rows); + pos=net_store_length(pos, (ulonglong) id); + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + int2store(pos,thd->server_status); + pos+=2; + + /* We can only return up to 65535 warnings in two bytes */ + uint tmp= min(thd->total_warn_count, 65535); + int2store(pos, tmp); + pos+= 2; + } + else if (net->return_status) // For 4.0 protocol + { + int2store(pos,thd->server_status); + pos+=2; + } + if (message) + pos=net_store_data((char*) pos, message, strlen(message)); + VOID(my_net_write(net,buff,(uint) (pos-buff))); + VOID(net_flush(net)); + DBUG_VOID_RETURN; +} + + +/* + Send eof (= end of result set) to the client + + SYNOPSIS + send_eof() + thd Thread handler + no_flush Set to 1 if there will be more data to the client, + like in send_fields(). + + DESCRIPTION + The eof packet has the following structure + + 254 Marker (1 byte) + warning_count Stored in 2 bytes; New in 4.1 protocol + status_flag Stored in 2 bytes; + For flags like SERVER_STATUS_MORE_RESULTS + + Note that the warning count will not be sent if 'no_flush' is set as + we don't want to report the warning count until all data is sent to the + client. +*/ + +void +send_eof(THD *thd, bool no_flush) +{ + static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ + NET *net= &thd->net; + DBUG_ENTER("send_eof"); + if (net->vio != 0) + { + if (!no_flush && (thd->client_capabilities & CLIENT_PROTOCOL_41)) + { + uchar buff[5]; + uint tmp= min(thd->total_warn_count, 65535); + buff[0]=254; + int2store(buff+1, tmp); + int2store(buff+3, 0); // No flags yet + VOID(my_net_write(net,(char*) buff,5)); + VOID(net_flush(net)); + } + else + { + VOID(my_net_write(net,eof_buff,1)); + if (!no_flush) + VOID(net_flush(net)); + } + } + DBUG_VOID_RETURN; +} + + +/**************************************************************************** + Store a field length in logical packet + + This is used to code the string length for normal protocol +****************************************************************************/ + +char * +net_store_length(char *pkg, ulonglong length) +{ + uchar *packet=(uchar*) pkg; + if (length < LL(251)) + { + *packet=(uchar) length; + return (char*) packet+1; + } + /* 251 is reserved for NULL */ + if (length < LL(65536)) + { + *packet++=252; + int2store(packet,(uint) length); + return (char*) packet+2; + } + if (length < LL(16777216)) + { + *packet++=253; + int3store(packet,(ulong) length); + return (char*) packet+3; + } + *packet++=254; + int8store(packet,length); + return (char*) packet+9; +} + + +/* + Faster net_store_length when we know length is a 32 bit integer +*/ + +char *net_store_length(char *pkg, uint length) +{ + uchar *packet=(uchar*) pkg; + if (length < 251) + { + *packet=(uchar) length; + return (char*) packet+1; + } + *packet++=252; + int2store(packet,(uint) length); + return (char*) packet+2; +} + + +/* + Used internally for storing strings in packet +*/ + +static bool net_store_data(String *packet, const char *from, uint length) +{ + ulong packet_length=packet->length(); + if (packet_length+5+length > packet->alloced_length() && + packet->realloc(packet_length+5+length)) + return 1; + char *to=(char*) net_store_length((char*) packet->ptr()+packet_length, + (ulonglong) length); + memcpy(to,from,length); + packet->length((uint) (to+length-packet->ptr())); + return 0; +} + +/**************************************************************************** + Functions used by the protocol functions (like send_ok) to store strings + and numbers in the header result packet. +****************************************************************************/ + +/* The following will only be used for short strings < 65K */ + +char *net_store_data(char *to,const char *from, uint length) +{ + to=net_store_length(to,length); + memcpy(to,from,length); + return to+length; +} + +char *net_store_data(char *to,int32 from) +{ + char buff[20]; + uint length=(uint) (int10_to_str(from,buff,10)-buff); + to=net_store_length(to,length); + memcpy(to,buff,length); + return to+length; +} + +char *net_store_data(char *to,longlong from) +{ + char buff[22]; + uint length=(uint) (longlong10_to_str(from,buff,10)-buff); + to=net_store_length(to,length); + memcpy(to,buff,length); + return to+length; +} + +/* + Function called by my_net_init() to set some check variables +*/ + +extern "C" { +void my_net_local_init(NET *net) +{ + net->max_packet= (uint) global_system_variables.net_buffer_length; + net->read_timeout= (uint) global_system_variables.net_read_timeout; + net->write_timeout=(uint) global_system_variables.net_write_timeout; + net->retry_count= (uint) global_system_variables.net_retry_count; + net->max_packet_size= max(global_system_variables.net_buffer_length, + global_system_variables.max_allowed_packet); +} +} + + +/***************************************************************************** + Default Protocol functions +*****************************************************************************/ + +void Protocol::init(THD *thd_arg) +{ + thd=thd_arg; + convert=thd->variables.convert_set; + packet= &thd->packet; +#ifndef DEBUG_OFF + field_types= 0; +#endif +} + +/* + Send name and type of result to client. + + SYNOPSIS + send_fields() + THD Thread data object + list List of items to send to client + convert object used to convertation to another character set + flag Bit mask with the following functions: + 1 send number of rows + 2 send default values + + DESCRIPTION + Sum fields has table name empty and field_name. + Uses send_fields_convert() and send_fields() depending on + if we have an active character set convert or not. + + RETURN VALUES + 0 ok + 1 Error (Note that in this case the error is not sent to the client) +*/ + +bool Protocol::send_fields(List<Item> *list, uint flag) +{ + List_iterator_fast<Item> it(*list); + Item *item; + char buff[80]; + String tmp((char*) buff,sizeof(buff),default_charset_info); + Protocol_simple prot(thd); + String *packet= prot.storage_packet(); + DBUG_ENTER("send_fields"); + + if (flag & 1) + { // Packet with number of elements + char *pos=net_store_length(buff, (uint) list->elements); + (void) my_net_write(&thd->net, buff,(uint) (pos-buff)); + } + +#ifndef DEBUG_OFF + field_types= (enum_field_types*) thd->alloc(sizeof(field_types) * + list->elements); + uint count= 0; +#endif + + while ((item=it++)) + { + char *pos; + Send_field field; + item->make_field(&field); + prot.prepare_for_resend(); + + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + if (prot.store(field.db_name, (uint) strlen(field.db_name)) || + prot.store(field.table_name, (uint) strlen(field.table_name)) || + prot.store(field.org_table_name, + (uint) strlen(field.org_table_name)) || + prot.store(field.col_name, (uint) strlen(field.col_name)) || + prot.store(field.org_col_name, (uint) strlen(field.org_col_name))) + goto err; + } + else + { + if (prot.store(field.table_name, (uint) strlen(field.table_name)) || + prot.store(field.col_name, (uint) strlen(field.col_name))) + goto err; + } + if (packet->realloc(packet->length()+10)) + goto err; + pos= (char*) packet->ptr()+packet->length(); + +#ifdef TO_BE_DELETED_IN_6 + if (!(thd->client_capabilities & CLIENT_LONG_FLAG)) + { + packet->length(packet->length()+9); + pos[0]=3; int3store(pos+1,field.length); + pos[4]=1; pos[5]=field.type; + pos[6]=2; pos[7]=(char) field.flags; pos[8]= (char) field.decimals; + } + else +#endif + { + packet->length(packet->length()+10); + pos[0]=3; int3store(pos+1,field.length); + pos[4]=1; pos[5]=field.type; + pos[6]=3; int2store(pos+7,field.flags); pos[9]= (char) field.decimals; + } + if (flag & 2) + item->send(&prot, &tmp); // Send default value + if (prot.write()) + break; /* purecov: inspected */ +#ifndef DEBUG_OFF + field_types[count++]= field.type; +#endif + } + + send_eof(thd); + DBUG_RETURN(prepare_for_send(list)); + +err: + send_error(thd,ER_OUT_OF_RESOURCES); /* purecov: inspected */ + DBUG_RETURN(1); /* purecov: inspected */ +} + + +bool Protocol::write() +{ + DBUG_ENTER("Protocol::write"); + DBUG_RETURN(my_net_write(&thd->net, packet->ptr(), packet->length())); +} + + +/* + Send \0 end terminated string + + SYNOPSIS + store() + from NullS or \0 terminated string + + NOTES + In most cases one should use store(from, length) instead of this function + + RETURN VALUES + 0 ok + 1 error +*/ + +bool Protocol::store(const char *from) +{ + if (!from) + return store_null(); + uint length= strlen(from); + return store(from, length); +} + + +/* + Send a set of strings as one long string with ',' in between +*/ + +bool Protocol::store(I_List<i_string>* str_list) +{ + char buf[256]; + String tmp(buf, sizeof(buf), default_charset_info); + tmp.length(0); + I_List_iterator<i_string> it(*str_list); + i_string* s; + + while ((s=it++)) + { + if (tmp.length()) + tmp.append(','); + tmp.append(s->ptr); + } + + return store((char*) tmp.ptr(), tmp.length()); +} + + +/**************************************************************************** + Functions to handle the simple (default) protocol where everything is + This protocol is the one that is used by default between the MySQL server + and client when you are not using prepared statements. + + All data are sent as 'packed-string-length' followed by 'string-data' + +****************************************************************************/ + +void Protocol_simple::prepare_for_resend() +{ + packet->length(0); +#ifndef DEBUG_OFF + field_pos= 0; +#endif +} + +bool Protocol_simple::store_null() +{ +#ifndef DEBUG_OFF + field_pos++; +#endif + char buff[1]; + buff[0]= 251; + return packet->append(buff, sizeof(buff), PACKET_BUFFET_EXTRA_ALLOC); +} + +bool Protocol_simple::store(const char *from, uint length) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_STRING || + field_types[field_pos] == MYSQL_TYPE_VAR_STRING); + field_pos++; +#endif + if (convert) + return convert->store(packet, from, length); + return net_store_data(packet, from, length); +} + + +bool Protocol_simple::store_tiny(longlong from) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || field_types[field_pos++] == MYSQL_TYPE_TINY); +#endif + char buff[20]; + return net_store_data(packet,(char*) buff, + (uint) (int10_to_str((int) from,buff, -10)-buff)); +} + +bool Protocol_simple::store_short(longlong from) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_SHORT); +#endif + char buff[20]; + return net_store_data(packet,(char*) buff, + (uint) (int10_to_str((int) from,buff, -10)-buff)); +} + +bool Protocol_simple::store_long(longlong from) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || field_types[field_pos++] == MYSQL_TYPE_LONG); +#endif + char buff[20]; + return net_store_data(packet,(char*) buff, + (uint) (int10_to_str((int) from,buff, -10)-buff)); +} + + +bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_LONGLONG); +#endif + char buff[22]; + return net_store_data(packet,(char*) buff, + (uint) (longlong10_to_str(from,buff, + unsigned_flag ? 10 : -10)- + buff)); +} + + +bool Protocol_simple::store(float from, uint32 decimals, String *buffer) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_FLOAT); +#endif + buffer->set((double) from, decimals, thd->thd_charset); + return net_store_data(packet,(char*) buffer->ptr(), buffer->length()); +} + +bool Protocol_simple::store(double from, uint32 decimals, String *buffer) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_DOUBLE); +#endif + buffer->set(from, decimals, thd->thd_charset); + return net_store_data(packet,(char*) buffer->ptr(), buffer->length()); +} + + +bool Protocol_simple::store(Field *field) +{ +#ifndef DEBUG_OFF + field_pos++; +#endif + if (field->is_null()) + return store_null(); + char buff[MAX_FIELD_WIDTH]; + String tmp(buff,sizeof(buff),default_charset_info); + field->val_str(&tmp,&tmp); + if (convert) + return convert->store(packet, tmp.ptr(), tmp.length()); + return net_store_data(packet, tmp.ptr(), tmp.length()); +} + + +bool Protocol_simple::store(TIME *tm) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_DATETIME); +#endif + char buff[40]; + uint length; + length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d", + (int) tm->year, + (int) tm->month, + (int) tm->day, + (int) tm->hour, + (int) tm->minute, + (int) tm->second)); + return net_store_data(packet, (char*) buff, length); +} + + +bool Protocol_simple::store_date(TIME *tm) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_DATE); +#endif + char buff[40]; + uint length; + length= my_sprintf(buff,(buff, "%04d-%02d-%02d", + (int) tm->year, + (int) tm->month, + (int) tm->day)); + return net_store_data(packet, (char*) buff, length); +} + + +bool Protocol_simple::store_time(TIME *tm) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_TIME); +#endif + char buff[40]; + uint length; + length= my_sprintf(buff,(buff, "%s%ld:%02d:%02d", + tm->neg ? "-" : "", + (long) tm->day*3600L+(long) tm->hour, + (int) tm->minute, + (int) tm->second)); + return net_store_data(packet, (char*) buff, length); +} + + +/**************************************************************************** + Functions to handle the binary protocol used with prepared statements +****************************************************************************/ + +bool Protocol_prep::prepare_for_send(List<Item> *item_list) +{ + field_count=item_list->elements; + bit_fields= (field_count+3)/8; + if (packet->alloc(bit_fields)) + return 1; + /* prepare_for_resend will be called after this one */ + return 0; +} + + +void Protocol_prep::prepare_for_resend() +{ + packet->length(bit_fields); + bzero((char*) packet->ptr()+1, bit_fields-1); + packet[0]=1; // Marker for ok packet + field_pos=0; +} + + +bool Protocol_prep::store(const char *from,uint length) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_STRING || + field_types[field_pos] == MYSQL_TYPE_VAR_STRING); +#endif + field_pos++; + if (convert) + return convert->store(packet, from, length); + return net_store_data(packet, from, length); +} + + +bool Protocol_prep::store_null() +{ + uint offset=(field_pos+2)/8, bit= (1 << ((field_pos+2) & 7)); + /* Room for this as it's allocated in prepare_for_send */ + char *to= (char*) packet->ptr()+offset; + *to= (char) ((uchar) *to | (uchar) bit); + field_pos++; + return 0; +} + + +bool Protocol_prep::store_tiny(longlong from) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_TINY); +#endif + char buff[1]; + field_pos++; + buff[0]= (uchar) from; + return packet->append(buff, sizeof(buff), PACKET_BUFFET_EXTRA_ALLOC); +} + + +bool Protocol_prep::store_short(longlong from) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_SHORT); +#endif + field_pos++; + char *to= packet->prep_append(2, PACKET_BUFFET_EXTRA_ALLOC); + if (!to) + return 1; + int2store(to, (int) from); + return 0; +} + + +bool Protocol_prep::store_long(longlong from) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_LONG); +#endif + field_pos++; + char *to= packet->prep_append(4, PACKET_BUFFET_EXTRA_ALLOC); + if (!to) + return 1; + int4store(to, from); + return 0; +} + + +bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_LONGLONG); +#endif + field_pos++; + char *to= packet->prep_append(8, PACKET_BUFFET_EXTRA_ALLOC); + if (!to) + return 1; + int8store(to, from); + return 0; +} + + +bool Protocol_prep::store(float from, uint32 decimals, String *buffer) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_FLOAT); +#endif + field_pos++; + char *to= packet->prep_append(4, PACKET_BUFFET_EXTRA_ALLOC); + if (!to) + return 1; + float4store(to, from); + return 0; +} + + +bool Protocol_prep::store(double from, uint32 decimals, String *buffer) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_DOUBLE); +#endif + field_pos++; + char *to= packet->prep_append(8, PACKET_BUFFET_EXTRA_ALLOC); + if (!to) + return 1; + float8store(to, from); + return 0; +} + + +bool Protocol_prep::store(Field *field) +{ + /* + We should not count up field_pos here as send_binary() will call another + protocol function to do this for us + */ + if (field->is_null()) + return store_null(); + return field->send_binary(this); +} + + +bool Protocol_prep::store(TIME *tm) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_DATETIME || + field_types[field_pos] == MYSQL_TYPE_DATE); +#endif + char buff[12],*pos; + uint length; + field_pos++; + pos= buff+1; + + int2store(pos, tm->year); + int2store(pos+2, tm->month); + int2store(pos+3, tm->day); + int2store(pos+4, tm->hour); + int2store(pos+5, tm->minute); + int2store(pos+6, tm->second); + int4store(pos+7, tm->second_part); + if (tm->second_part) + length=11; + else if (tm->hour || tm->minute || tm->second) + length=7; + else if (tm->year || tm->month || tm->day) + length=4; + else + length=0; + buff[0]=(char) length; // Length is stored first + return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC); +} + +bool Protocol_prep::store_date(TIME *tm) +{ + tm->hour= tm->minute= tm->second=0; + tm->second_part= 0; + return Protocol_prep::store(tm); +} + + +bool Protocol_prep::store_time(TIME *tm) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_TIME); +#endif + char buff[15],*pos; + uint length; + field_pos++; + pos= buff+1; + pos[0]= tm->neg ? 1 : 0; + int4store(pos+1, tm->day); + int2store(pos+5, tm->hour); + int2store(pos+7, tm->minute); + int2store(pos+9, tm->second); + int4store(pos+11, tm->second_part); + if (tm->second_part) + length=14; + else if (tm->hour || tm->minute || tm->second || tm->day) + length=10; + else + length=0; + buff[0]=(char) length; // Length is stored first + return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC); +} diff --git a/sql/protocol.h b/sql/protocol.h new file mode 100644 index 00000000000..b3ab0a2b31d --- /dev/null +++ b/sql/protocol.h @@ -0,0 +1,131 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef __GNUC__ +#pragma interface /* gcc class implementation */ +#endif + +#define PACKET_BUFFET_EXTRA_ALLOC 1024 + +class CONVERT; +class i_string; +class THD; + +class Protocol +{ +protected: + THD *thd; + String *packet; + uint field_pos; +#ifndef DEBUG_OFF + enum enum_field_types *field_types; +#endif + +public: + CONVERT *convert; + + Protocol() {} + Protocol(THD *thd) { init(thd); } + void init(THD* thd); + bool send_fields(List<Item> *list, uint flag); + bool store(I_List<i_string> *str_list); + bool store(const char *from); + String *storage_packet() { return packet; } + inline void free() { packet->free(); } + bool write(); + inline bool store(uint32 from) + { return store_long((longlong) from); } + inline bool store(longlong from) + { return store_longlong((longlong) from, 0); } + inline bool store(ulonglong from) + { return store_longlong((longlong) from, 1); } + + virtual bool prepare_for_send(List<Item> *item_list) { return 0;} + virtual void prepare_for_resend()=0; + + virtual bool store_null()=0; + virtual bool store_tiny(longlong from)=0; + virtual bool store_short(longlong from)=0; + virtual bool store_long(longlong from)=0; + virtual bool store_longlong(longlong from, bool unsigned_flag)=0; + virtual bool store(const char *from, uint length)=0; + virtual bool store(float from, uint32 decimals, String *buffer)=0; + virtual bool store(double from, uint32 decimals, String *buffer)=0; + virtual bool store(TIME *time)=0; + virtual bool store_date(TIME *time)=0; + virtual bool store_time(TIME *time)=0; + virtual bool store(Field *field)=0; +}; + + +/* Class used for the old (MySQL 4.0 protocol) */ + +class Protocol_simple :public Protocol +{ +public: + Protocol_simple() {} + Protocol_simple(THD *thd) :Protocol(thd) {} + virtual void prepare_for_resend(); + virtual bool store_null(); + virtual bool store_tiny(longlong from); + virtual bool store_short(longlong from); + virtual bool store_long(longlong from); + virtual bool store_longlong(longlong from, bool unsigned_flag); + virtual bool store(const char *from, uint length); + virtual bool store(TIME *time); + virtual bool store_date(TIME *time); + virtual bool store_time(TIME *time); + virtual bool store(float nr, uint32 decimals, String *buffer); + virtual bool store(double from, uint32 decimals, String *buffer); + virtual bool store(Field *field); +}; + + +class Protocol_prep :public Protocol +{ +private: + uint field_count, bit_fields; +public: + Protocol_prep() {} + Protocol_prep(THD *thd) :Protocol(thd) {} + virtual bool prepare_for_send(List<Item> *item_list); + virtual void prepare_for_resend(); + virtual bool store_null(); + virtual bool store_tiny(longlong from); + virtual bool store_short(longlong from); + virtual bool store_long(longlong from); + virtual bool store_longlong(longlong from, bool unsigned_flag); + virtual bool store(const char *from,uint length); + virtual bool store(TIME *time); + virtual bool store_date(TIME *time); + virtual bool store_time(TIME *time); + virtual bool store(float nr, uint32 decimals, String *buffer); + virtual bool store(double from, uint32 decimals, String *buffer); + virtual bool store(Field *field); +}; + + +void send_warning(THD *thd, uint sql_errno, const char *err=0); +void net_printf(THD *thd,uint sql_errno, ...); +void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, + const char *info=0); +void send_eof(THD *thd, bool no_flush=0); +void net_send_error(NET *net, uint sql_errno, const char *err); +char *net_store_length(char *packet,ulonglong length); +char *net_store_length(char *packet,uint length); +char *net_store_data(char *to,const char *from, uint length); +char *net_store_data(char *to,int32 from); +char *net_store_data(char *to,longlong from); diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 785a253b1ac..16b2eedd3b2 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -416,6 +416,7 @@ static Slave_log_event* find_slave_event(IO_CACHE* log, int show_new_master(THD* thd) { + Protocol *protocol= thd->protocol; DBUG_ENTER("show_new_master"); List<Item> field_list; char errmsg[SLAVE_ERRMSG_SIZE]; @@ -431,15 +432,15 @@ int show_new_master(THD* thd) } else { - String* packet = &thd->packet; field_list.push_back(new Item_empty_string("Log_name", 20)); - field_list.push_back(new Item_empty_string("Log_pos", 20)); - if (send_fields(thd, field_list, 1)) + field_list.push_back(new Item_return_int("Log_pos", 10, + MYSQL_TYPE_LONGLONG)); + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); - packet->length(0); - net_store_data(packet, lex_mi->log_file_name); - net_store_data(packet, (longlong)lex_mi->pos); - if (my_net_write(&thd->net, packet->ptr(), packet->length())) + protocol->prepare_for_resend(); + protocol->store(lex_mi->log_file_name); + protocol->store((ulonglong) lex_mi->pos); + if (protocol->write()) DBUG_RETURN(-1); send_eof(thd); DBUG_RETURN(0); @@ -580,21 +581,24 @@ int show_slave_hosts(THD* thd) { List<Item> field_list; NET* net = &thd->net; - String* packet = &thd->packet; + Protocol *protocol= thd->protocol; DBUG_ENTER("show_slave_hosts"); - field_list.push_back(new Item_empty_string("Server_id", 20)); + field_list.push_back(new Item_return_int("Server_id", 10, + MYSQL_TYPE_LONG)); field_list.push_back(new Item_empty_string("Host", 20)); if (opt_show_slave_auth_info) { field_list.push_back(new Item_empty_string("User",20)); field_list.push_back(new Item_empty_string("Password",20)); } - field_list.push_back(new Item_empty_string("Port",20)); - field_list.push_back(new Item_empty_string("Rpl_recovery_rank", 20)); - field_list.push_back(new Item_empty_string("Master_id", 20)); + field_list.push_back(new Item_return_int("Port", 7, MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Rpl_recovery_rank", 7, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Master_id", 10, + MYSQL_TYPE_LONG)); - if (send_fields(thd, field_list, 1)) + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); pthread_mutex_lock(&LOCK_slave_list); @@ -602,18 +606,18 @@ int show_slave_hosts(THD* thd) for (uint i = 0; i < slave_list.records; ++i) { SLAVE_INFO* si = (SLAVE_INFO*) hash_element(&slave_list, i); - packet->length(0); - net_store_data(packet, si->server_id); - net_store_data(packet, si->host); + protocol->prepare_for_resend(); + protocol->store((uint32) si->server_id); + protocol->store(si->host); if (opt_show_slave_auth_info) { - net_store_data(packet, si->user); - net_store_data(packet, si->password); + protocol->store(si->user); + protocol->store(si->password); } - net_store_data(packet, (uint32) si->port); - net_store_data(packet, si->rpl_recovery_rank); - net_store_data(packet, si->master_id); - if (my_net_write(net, (char*)packet->ptr(), packet->length())) + protocol->store((uint32) si->port); + protocol->store((uint32) si->rpl_recovery_rank); + protocol->store((uint32) si->master_id); + if (protocol->write()) { pthread_mutex_unlock(&LOCK_slave_list); DBUG_RETURN(-1); diff --git a/sql/slave.cc b/sql/slave.cc index f8acc592afa..7d3ec8d3dce 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1513,42 +1513,38 @@ err: *****************************************************************************/ int register_slave_on_master(MYSQL* mysql) { - String packet; - char buf[4]; + char buf[1024], *pos= buf; + uint report_host_len, report_user_len=0, report_password_len=0; if (!report_host) return 0; - - int4store(buf, server_id); - packet.append(buf, 4); - - net_store_data(&packet, report_host); + report_host_len= strlen(report_host); if (report_user) - net_store_data(&packet, report_user); - else - packet.append((char)0); - + report_user_len= strlen(report_user); if (report_password) - net_store_data(&packet, report_user); - else - packet.append((char)0); - - int2store(buf, (uint16)report_port); - packet.append(buf, 2); - int4store(buf, rpl_recovery_rank); - packet.append(buf, 4); - int4store(buf, 0); /* tell the master will fill in master_id */ - packet.append(buf, 4); - - if (mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*)packet.ptr(), - packet.length(), 0)) + report_password_len= strlen(report_password); + /* 30 is a good safety margin */ + if (report_host_len + report_user_len + report_password_len + 30 > + sizeof(buf)) + return 0; // safety + + int4store(pos, server_id); pos+= 4; + pos= net_store_data(pos, report_host, report_host_len); + pos= net_store_data(pos, report_user, report_user_len); + pos= net_store_data(pos, report_password, report_password_len); + int2store(pos, (uint16) report_port); pos+= 2; + int4store(pos, rpl_recovery_rank); pos+= 4; + /* The master will fill in master_id */ + int4store(pos, 0); pos+= 4; + + if (mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*) buf, + (uint) (pos- buf), 0)) { sql_print_error("Error on COM_REGISTER_SLAVE: %d '%s'", mc_mysql_errno(mysql), mc_mysql_error(mysql)); return 1; } - return 0; } @@ -1560,60 +1556,69 @@ int register_slave_on_master(MYSQL* mysql) int show_master_info(THD* thd, MASTER_INFO* mi) { // TODO: fix this for multi-master - DBUG_ENTER("show_master_info"); List<Item> field_list; + Protocol *protocol= thd->protocol; + DBUG_ENTER("show_master_info"); + field_list.push_back(new Item_empty_string("Master_Host", sizeof(mi->host))); field_list.push_back(new Item_empty_string("Master_User", sizeof(mi->user))); - field_list.push_back(new Item_empty_string("Master_Port", 6)); - field_list.push_back(new Item_empty_string("Connect_retry", 6)); + field_list.push_back(new Item_return_int("Master_Port", 7, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Connect_retry", 10, + MYSQL_TYPE_LONG)); field_list.push_back(new Item_empty_string("Master_Log_File", - FN_REFLEN)); - field_list.push_back(new Item_empty_string("Read_Master_Log_Pos", 12)); + FN_REFLEN)); + field_list.push_back(new Item_return_int("Read_Master_Log_Pos", 10, + MYSQL_TYPE_LONGLONG)); field_list.push_back(new Item_empty_string("Relay_Log_File", - FN_REFLEN)); - field_list.push_back(new Item_empty_string("Relay_Log_Pos", 12)); + FN_REFLEN)); + field_list.push_back(new Item_return_int("Relay_Log_Pos", 10, + MYSQL_TYPE_LONGLONG)); field_list.push_back(new Item_empty_string("Relay_Master_Log_File", - FN_REFLEN)); + FN_REFLEN)); field_list.push_back(new Item_empty_string("Slave_IO_Running", 3)); field_list.push_back(new Item_empty_string("Slave_SQL_Running", 3)); field_list.push_back(new Item_empty_string("Replicate_do_db", 20)); field_list.push_back(new Item_empty_string("Replicate_ignore_db", 20)); - field_list.push_back(new Item_empty_string("Last_errno", 4)); + field_list.push_back(new Item_return_int("Last_errno", 4, MYSQL_TYPE_LONG)); field_list.push_back(new Item_empty_string("Last_error", 20)); - field_list.push_back(new Item_empty_string("Skip_counter", 12)); - field_list.push_back(new Item_empty_string("Exec_master_log_pos", 12)); - field_list.push_back(new Item_empty_string("Relay_log_space", 12)); - if (send_fields(thd, field_list, 1)) + field_list.push_back(new Item_return_int("Skip_counter", 10, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Exec_master_log_pos", 10, + MYSQL_TYPE_LONGLONG)); + field_list.push_back(new Item_return_int("Relay_log_space", 10, + MYSQL_TYPE_LONGLONG)); + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); if (mi->host[0]) { String *packet= &thd->packet; - packet->length(0); + protocol->prepare_for_resend(); pthread_mutex_lock(&mi->data_lock); pthread_mutex_lock(&mi->rli.data_lock); - net_store_data(packet, mi->host); - net_store_data(packet, mi->user); - net_store_data(packet, (uint32) mi->port); - net_store_data(packet, (uint32) mi->connect_retry); - net_store_data(packet, mi->master_log_name); - net_store_data(packet, (longlong) mi->master_log_pos); - net_store_data(packet, mi->rli.relay_log_name + + protocol->store(mi->host); + protocol->store(mi->user); + protocol->store((uint32) mi->port); + protocol->store((uint32) mi->connect_retry); + protocol->store(mi->master_log_name); + protocol->store((ulonglong) mi->master_log_pos); + protocol->store(mi->rli.relay_log_name + dirname_length(mi->rli.relay_log_name)); - net_store_data(packet, (longlong) mi->rli.relay_log_pos); - net_store_data(packet, mi->rli.master_log_name); - net_store_data(packet, mi->slave_running ? "Yes":"No"); - net_store_data(packet, mi->rli.slave_running ? "Yes":"No"); - net_store_data(packet, &replicate_do_db); - net_store_data(packet, &replicate_ignore_db); - net_store_data(packet, (uint32)mi->rli.last_slave_errno); - net_store_data(packet, mi->rli.last_slave_error); - net_store_data(packet, mi->rli.slave_skip_counter); - net_store_data(packet, (longlong) mi->rli.master_log_pos); - net_store_data(packet, (longlong) mi->rli.log_space_total); + protocol->store((ulonglong) mi->rli.relay_log_pos); + protocol->store(mi->rli.master_log_name); + protocol->store(mi->slave_running ? "Yes":"No"); + protocol->store(mi->rli.slave_running ? "Yes":"No"); + protocol->store(&replicate_do_db); + protocol->store(&replicate_ignore_db); + protocol->store((uint32) mi->rli.last_slave_errno); + protocol->store(mi->rli.last_slave_error); + protocol->store((uint32) mi->rli.slave_skip_counter); + protocol->store((ulonglong) mi->rli.master_log_pos); + protocol->store((ulonglong) mi->rli.log_space_total); pthread_mutex_unlock(&mi->rli.data_lock); pthread_mutex_unlock(&mi->data_lock); @@ -1640,8 +1645,7 @@ bool flush_master_info(MASTER_INFO* mi) my_b_printf(file, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n", mi->master_log_name, llstr(mi->master_log_pos, lbuf), mi->host, mi->user, - mi->password, mi->port, mi->connect_retry - ); + mi->password, mi->port, mi->connect_retry); flush_io_cache(file); DBUG_RETURN(0); } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 59f4d920304..0c68b5e92ef 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2776,6 +2776,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) int error = 0; ACL_USER *acl_user; ACL_DB *acl_db; char buff[1024]; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysql_show_grants"); LINT_INIT(acl_user); @@ -2822,7 +2823,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) strxmov(buff,"Grants for ",lex_user->user.str,"@", lex_user->host.str,NullS); field_list.push_back(field); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(-1); rw_wrlock(&LOCK_grant); @@ -2931,12 +2932,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append(buff,p-buff); } } - thd->packet.length(0); - net_store_data(&thd->packet,global.ptr(),global.length()); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(), - thd->packet.length())) + protocol->prepare_for_resend(); + protocol->store(global.ptr(),global.length()); + if (protocol->write()) { - error=-1; goto end; + error=-1; + goto end; } } @@ -2987,10 +2988,9 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) db.append ('\''); if (want_access & GRANT_ACL) db.append(" WITH GRANT OPTION",18); - thd->packet.length(0); - net_store_data(&thd->packet,db.ptr(),db.length()); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(), - thd->packet.length())) + protocol->prepare_for_resend(); + protocol->store(db.ptr(),db.length()); + if (protocol->write()) { error=-1; goto end; @@ -3075,10 +3075,9 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append('\''); if (want_access & GRANT_ACL) global.append(" WITH GRANT OPTION",18); - thd->packet.length(0); - net_store_data(&thd->packet,global.ptr(),global.length()); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(), - thd->packet.length())) + protocol->prepare_for_resend(); + protocol->store(global.ptr(),global.length()); + if (protocol->write()) { error= -1; break; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e2b36106fb0..87cc0d616a9 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -196,250 +196,6 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild) } -/* - Send name and type of result to client converted to a given char set - - SYNOPSIS - send_convert_fields() - THD Thread data object - list List of items to send to client - convert object used to convertation to another character set - flag Bit mask with the following functions: - 2 send default values - 4 Don't convert field names - - DESCRIPTION - Sum fields has table name empty and field_name. - - RETURN VALUES - 0 ok - 1 Error (Note that in this case the error is not sent to the client) -*/ - -bool -send_convert_fields(THD *thd,List<Item> &list,CONVERT *convert,uint flag) -{ - List_iterator_fast<Item> it(list); - Item *item; - char buff[80]; - String tmp((char*) buff,sizeof(buff),default_charset_info); - String *res,*packet= &thd->packet; - DBUG_ENTER("send_convert_fields"); - - while ((item=it++)) - { - char *pos; - Send_field field; - item->make_field(&field); - packet->length(0); - - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - if (convert->store(packet,field.db_name, - (uint) strlen(field.db_name)) || - convert->store(packet,field.table_name, - (uint) strlen(field.table_name)) || - convert->store(packet,field.org_table_name, - (uint) strlen(field.org_table_name)) || - convert->store(packet,field.col_name, - (uint) strlen(field.col_name)) || - convert->store(packet,field.org_col_name, - (uint) strlen(field.org_col_name)) || - packet->realloc(packet->length()+10)) - goto err; - } - else - { - if (convert->store(packet,field.table_name, - (uint) strlen(field.table_name)) || - convert->store(packet,field.col_name, - (uint) strlen(field.col_name)) || - packet->realloc(packet->length()+10)) - goto err; - } - pos= (char*) packet->ptr()+packet->length(); - - if (!(thd->client_capabilities & CLIENT_LONG_FLAG)) - { - packet->length(packet->length()+9); - pos[0]=3; int3store(pos+1,field.length); - pos[4]=1; pos[5]=field.type; - pos[6]=2; pos[7]=(char) field.flags; pos[8]= (char) field.decimals; - } - else - { - packet->length(packet->length()+10); - pos[0]=3; int3store(pos+1,field.length); - pos[4]=1; pos[5]=field.type; - pos[6]=3; int2store(pos+7,field.flags); pos[9]= (char) field.decimals; - } - if (flag & 2) - { // Send default value - if (!(res=item->val_str(&tmp))) - { - if (net_store_null(packet)) - goto err; - } - else if (convert->store(packet,res->ptr(),res->length())) - goto err; - } - if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length())) - break; /* purecov: inspected */ - } - DBUG_RETURN(0); - -err: - DBUG_RETURN(1); -} - - -/* - Send name and type of result to client. - - SYNOPSIS - send_non_convert_fields() - THD Thread data object - list List of items to send to client - flag Bit mask with the following functions: - 2 send default values - 4 Don't convert field names - - DESCRIPTION - Sum fields has table name empty and field_name. - - RETURN VALUES - 0 ok - 1 Error -*/ - -bool -send_non_convert_fields(THD *thd,List<Item> &list,uint flag) -{ - List_iterator_fast<Item> it(list); - Item *item; - char buff[80]; - - String tmp((char*) buff,sizeof(buff),default_charset_info); - String *res,*packet= &thd->packet; - - while ((item=it++)) - { - char *pos; - Send_field field; - item->make_field(&field); - packet->length(0); - - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - if (net_store_data(packet,field.db_name) || - net_store_data(packet,field.table_name) || - net_store_data(packet,field.org_table_name) || - net_store_data(packet,field.col_name) || - net_store_data(packet,field.org_col_name) || - packet->realloc(packet->length()+10)) - return 1; - } - else - { - if (net_store_data(packet,field.table_name) || - net_store_data(packet,field.col_name) || - packet->realloc(packet->length()+10)) - return 1; - } - - pos= (char*) packet->ptr()+packet->length(); - - if (!(thd->client_capabilities & CLIENT_LONG_FLAG)) - { - packet->length(packet->length()+9); - pos[0]=3; int3store(pos+1,field.length); - pos[4]=1; pos[5]=field.type; - pos[6]=2; pos[7]=(char) field.flags; pos[8]= (char) field.decimals; - } - else - { - packet->length(packet->length()+10); - pos[0]=3; int3store(pos+1,field.length); - pos[4]=1; pos[5]=field.type; - pos[6]=3; int2store(pos+7,field.flags); pos[9]= (char) field.decimals; - } - if (flag & 2) - { // Send default value - if (!(res=item->val_str(&tmp))) - { - if (net_store_null(packet)) - return 1; - } - else if (net_store_data(packet,res->ptr(),res->length())) - return 1; - } - if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length())) - break; - } - return 0; -} - - -/* - Send name and type of result to client. - - SYNOPSIS - send_fields() - THD Thread data object - list List of items to send to client - convert object used to convertation to another character set - flag Bit mask with the following functions: - 1 send number of rows - 2 send default values - 4 Don't convert field names - - DESCRIPTION - Sum fields has table name empty and field_name. - Uses send_fields_convert() and send_fields() depending on - if we have an active character set convert or not. - - RETURN VALUES - 0 ok - 1 Error (Note that in this case the error is not sent to the client) -*/ - -bool -send_fields(THD *thd, List<Item> &list, uint flag) -{ - char buff[9]; // Big enough for store_length - CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->variables.convert_set; - DBUG_ENTER("send_fields"); - - if (thd->fatal_error) // We have got an error - goto err; - - if (flag & 1) - { // Packet with number of elements - char *pos=net_store_length(buff, (uint) list.elements); - (void) my_net_write(&thd->net, buff,(uint) (pos-buff)); - } - - /* - Avoid check conditions on convert() for each field - by having two different functions - */ - if (convert) - { - if (send_convert_fields(thd, list, convert, flag)) - goto err; - } - else if (send_non_convert_fields(thd, list, flag)) - goto err; - - send_eof(thd); - DBUG_RETURN(0); - -err: - send_error(thd,ER_OUT_OF_RESOURCES); /* purecov: inspected */ - DBUG_RETURN(1); /* purecov: inspected */ -} - - /***************************************************************************** * Functions to free open table cache ****************************************************************************/ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ebd1d9d2b3c..dedf496db3c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -152,6 +152,11 @@ THD::THD():user_time(0), fatal_error(0), (qsort_cmp2) compare_prep_stmt, 1, (tree_element_free) free_prep_stmt, 0); + /* Protocol */ + protocol= &protocol_simple; // Default protocol + protocol_simple.init(this); + protocol_prep.init(this); + #ifdef USING_TRANSACTIONS bzero((char*) &transaction,sizeof(transaction)); if (opt_using_transactions) @@ -438,7 +443,7 @@ int THD::send_explain_fields(select_result *result) { List<Item> field_list; Item *item; - field_list.push_back(new Item_int("id",0,3)); + field_list.push_back(new Item_return_int("id",3, MYSQL_TYPE_LONGLONG)); field_list.push_back(new Item_empty_string("select_type",19)); field_list.push_back(new Item_empty_string("table",NAME_LEN)); field_list.push_back(new Item_empty_string("type",10)); @@ -447,12 +452,13 @@ int THD::send_explain_fields(select_result *result) item->maybe_null=1; field_list.push_back(item=new Item_empty_string("key",NAME_LEN)); item->maybe_null=1; - field_list.push_back(item=new Item_int("key_len",0,3)); + field_list.push_back(item=new Item_return_int("key_len",3, + MYSQL_TYPE_LONGLONG)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("ref", NAME_LEN*MAX_REF_PARTS)); item->maybe_null=1; - field_list.push_back(new Item_real("rows",0.0,0,10)); + field_list.push_back(new Item_return_int("rows",10, MYSQL_TYPE_LONGLONG)); field_list.push_back(new Item_empty_string("Extra",255)); return (result->send_fields(field_list,1)); } @@ -503,7 +509,7 @@ sql_exchange::sql_exchange(char *name,bool flag) bool select_send::send_fields(List<Item> &list,uint flag) { - return ::send_fields(thd,list,flag); + return thd->protocol->send_fields(&list,flag); } @@ -511,35 +517,32 @@ bool select_send::send_fields(List<Item> &list,uint flag) bool select_send::send_data(List<Item> &items) { - List_iterator_fast<Item> li(items); - String *packet= &thd->packet; - DBUG_ENTER("send_data"); - if (unit->offset_limit_cnt) { // using limit offset,count unit->offset_limit_cnt--; - DBUG_RETURN(0); } - packet->length(0); // Reset packet + + List_iterator_fast<Item> li(items); + Protocol *protocol= thd->protocol; + char buff[MAX_FIELD_WIDTH]; + String buffer(buff, sizeof(buff), system_charset_info); + DBUG_ENTER("send_data"); + + protocol->prepare_for_resend(); Item *item; while ((item=li++)) { - if (item->send(thd, packet)) + if (item->send(protocol, &buffer)) { - packet->free(); // Free used + protocol->free(); // Free used buffer my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - DBUG_RETURN(1); + break; } } thd->sent_row_count++; if (!thd->net.report_error) - { - DBUG_RETURN(my_net_write(&thd->net, - (char*) packet->ptr(), - packet->length())); - } - else - DBUG_RETURN(1); + DBUG_RETURN(protocol->write()); + DBUG_RETURN(1); } bool select_send::send_eof() diff --git a/sql/sql_class.h b/sql/sql_class.h index ca56d2dcdf5..50ab7919998 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -389,6 +389,9 @@ public: MEM_ROOT mem_root; // 1 command-life memory pool MEM_ROOT con_root; // connection-life memory MEM_ROOT warn_root; // For warnings and errors + Protocol *protocol; // Current protocol + Protocol_simple protocol_simple; // Normal protocol + Protocol_prep protocol_prep; // Binary protocol HASH user_vars; // hash for user variables TREE prepared_statements; String packet; // dynamic buffer for network I/O diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 85dfb38fa48..bca133bd63a 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -604,7 +604,8 @@ bool mysql_change_db(THD *thd, const char *name) } -int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create_info) +int mysqld_show_create_db(THD *thd, const char *dbname, + HA_CREATE_INFO *create_info) { int length; char path[FN_REFLEN], *to; @@ -613,7 +614,7 @@ int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create_i HA_CREATE_INFO create; CONVERT *convert=thd->variables.convert_set; uint create_options = create_info ? create_info->options : 0; - + Protocol *protocol=thd->protocol; DBUG_ENTER("mysql_show_create_db"); if (check_db_name(dbname)) @@ -663,12 +664,11 @@ int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create_i field_list.push_back(new Item_empty_string("Database",NAME_LEN)); field_list.push_back(new Item_empty_string("Create Database",1024)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); - String *packet = &thd->packet; - packet->length(0); - net_store_data(packet, convert, dbname); + protocol->prepare_for_resend(); + protocol->store(dbname, strlen(dbname)); to= strxmov(path, "CREATE DATABASE ", NullS); if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS) to= strxmov(to,"/*!32312 IF NOT EXISTS*/ ", NullS); @@ -678,11 +678,10 @@ int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create_i to= strxmov(to," /*!40100 DEFAULT CHARACTER SET ", create.table_charset->name,"*/",NullS); - net_store_data(packet, convert, path, (uint) (to-path)); + protocol->store(path, (uint) (to-path)); - if (my_net_write(&thd->net,(char*) packet->ptr(), packet->length())) + if (protocol->write()) DBUG_RETURN(1); - send_eof(thd); DBUG_RETURN(0); } diff --git a/sql/sql_error.cc b/sql/sql_error.cc index bba49cf818b..b208015a2bb 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -150,7 +150,7 @@ void store_warning(THD *thd, uint errcode, ...) */ static const char *warning_level_names[]= {"Note", "Warning", "Error", "?"}; - +static int warning_level_length[]= { 4, 7, 5, 1 }; my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show) { @@ -161,12 +161,13 @@ my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show) field_list.push_back(new Item_int("Code",0,4)); field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE)); - if (send_fields(thd,field_list,1)) + if (thd->protocol->send_fields(&field_list,1)) DBUG_RETURN(1); MYSQL_ERROR *err; SELECT_LEX *sel= &thd->lex.select_lex; ha_rows offset= sel->offset_limit, limit= sel->select_limit; + Protocol *protocol=thd->protocol; List_iterator_fast<MYSQL_ERROR> it(thd->warn_list); while ((err= it++)) @@ -179,11 +180,12 @@ my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show) offset--; continue; } - thd->packet.length(0); - net_store_data(&thd->packet,warning_level_names[err->level]); - net_store_data(&thd->packet,(uint32) err->code); - net_store_data(&thd->packet,err->msg); - if (my_net_write(&thd->net,(char*)thd->packet.ptr(),thd->packet.length())) + protocol->prepare_for_resend(); + protocol->store(warning_level_names[err->level], + warning_level_length[err->level]); + protocol->store((uint32) err->code); + protocol->store(err->msg, strlen(err->msg)); + if (protocol->write()) DBUG_RETURN(1); if (!--limit) break; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 6ea319a72e4..97703cd6b20 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -123,6 +123,9 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, List<Item> list; list.push_front(new Item_field(NULL,NULL,"*")); List_iterator<Item> it(list); + Protocol *protocol= thd->protocol; + char buff[MAX_FIELD_WIDTH]; + String buffer(buff, sizeof(buff), system_charset_info); uint num_rows; it++; @@ -131,7 +134,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it select_limit+=offset_limit; - send_fields(thd,list,1); + protocol->send_fields(&list,1); HANDLER_TABLES_HACK(thd); MYSQL_LOCK *lock=mysql_lock_tables(thd,&tables->table,1); @@ -141,7 +144,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, for (num_rows=0; num_rows < select_limit; ) { - switch(mode) { + switch (mode) { case RFIRST: err=keyname ? table->file->index_first(table->record[0]) : @@ -216,24 +219,24 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, if (!cond->val_int()) continue; } - if (num_rows>=offset_limit) + if (num_rows >= offset_limit) { if (!err) { String *packet = &thd->packet; Item *item; - packet->length(0); + protocol->prepare_for_resend(); it.rewind(); while ((item=it++)) { - if (item->send(thd,packet)) + if (item->send(thd->protocol, &buffer)) { - packet->free(); // Free used + protocol->free(); // Free used my_error(ER_OUT_OF_RESOURCES,MYF(0)); goto err; } } - my_net_write(&thd->net, (char*)packet->ptr(), packet->length()); + protocol->write(); } } num_rows++; @@ -249,26 +252,26 @@ err0: } /************************************************************************** - 2Monty: It could easily happen, that the following service functions are + Monty: It could easily happen, that the following service functions are already defined somewhere in the code, but I failed to find them. If this is the case, just say a word and I'll use old functions here. **************************************************************************/ -/* Note: this function differs from find_locked_table() because we're looking - here for alias, not real table name - */ +/* + Note: this function differs from find_locked_table() because we're looking + here for alias, not real table name +*/ + static TABLE **find_table_ptr_by_name(THD *thd, const char *db, const char *alias) { int dblen; TABLE **ptr; - if (!db || ! *db) - db= thd->db ? thd->db : ""; dblen=strlen(db)+1; - ptr=&(thd->handler_tables); + ptr= &(thd->handler_tables); - for (TABLE *table=*ptr; table ; table=*ptr) + for (TABLE *table= *ptr; table ; table= *ptr) { if (!memcmp(table->table_cache_key, db, dblen) && !my_strcasecmp(system_charset_info,table->table_name,alias)) diff --git a/sql/sql_help.cc b/sql/sql_help.cc index d2bea9ba44b..db28823a43d 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -219,22 +219,21 @@ int search_categories(THD *thd, DBUG_RETURN(count); } -int send_variant_2_list(THD *thd, List<String> *names, my_bool is_category) +int send_variant_2_list(Protocol *protocol, List<String> *names, + my_bool is_category) { DBUG_ENTER("send_names"); List_iterator<String> it(*names); String *cur_name; - String *packet= &thd->packet; while ((cur_name = it++)) { - packet->length(0); - net_store_data(packet, cur_name->ptr()); - net_store_data(packet, is_category ? "Y" : "N"); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->prepare_for_resend(); + protocol->store(cur_name->ptr()); + protocol->store(is_category ? "Y" : "N"); + if (protocol->write()) DBUG_RETURN(-1); } - DBUG_RETURN(0); } @@ -296,43 +295,44 @@ int get_all_names_for_category(THD *thd,MI_INFO *file_leafs, DBUG_RETURN(0); } -int send_answer_1(THD *thd, const char *s1, const char *s2, +int send_answer_1(Protocol *protocol, const char *s1, const char *s2, const char *s3, const char *s4) { DBUG_ENTER("send_answer_1"); List<Item> field_list; - field_list.push_back(new Item_empty_string("name",64)); - field_list.push_back(new Item_empty_string("is_category",1)); - field_list.push_back(new Item_empty_string("description",1000)); - field_list.push_back(new Item_empty_string("example",1000)); + field_list.push_back(new Item_empty_string("Name",64)); + field_list.push_back(new Item_empty_string("Category",1)); + field_list.push_back(new Item_empty_string("Description",1000)); + field_list.push_back(new Item_empty_string("Example",1000)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); - String *packet= &thd->packet; - packet->length(0); - net_store_data(packet, s1); - net_store_data(packet, s2); - net_store_data(packet, s3); - net_store_data(packet, s4); - - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->prepare_for_resend(); + protocol->store(s1); + protocol->store(s2); + protocol->store(s3); + protocol->store(s4); + if (protocol->write()) DBUG_RETURN(-1); DBUG_RETURN(0); } -int send_header_2(THD *thd) + +int send_header_2(Protocol *protocol) { DBUG_ENTER("send_header2"); List<Item> field_list; - field_list.push_back(new Item_empty_string("name",64)); - field_list.push_back(new Item_empty_string("is_category",1)); - DBUG_RETURN(send_fields(thd,field_list,1)); + field_list.push_back(new Item_empty_string("Name",64)); + field_list.push_back(new Item_empty_string("Category",1)); + DBUG_RETURN(protocol->send_fields(&field_list,1)); } -int mysqld_help (THD *thd, const char *mask) + +int mysqld_help(THD *thd, const char *mask) { + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_help"); MI_INFO *file_leafs= 0; @@ -345,7 +345,7 @@ int mysqld_help (THD *thd, const char *mask) int count= search_functions(file_leafs, mask, &function_list,&name,&description,&example); - if (count<0) + if (count < 0) { res= 1; goto end; @@ -371,31 +371,31 @@ int mysqld_help (THD *thd, const char *mask) example.append(*cur_leaf); example.append("\n",1); } - if ((res= send_answer_1(thd, categories_list.head()->ptr(), - "Y","",example.ptr()))) + if ((res= send_answer_1(protocol, categories_list.head()->ptr(), + "Y","",example.ptr()))) goto end; } else { - if ((res= send_header_2(thd)) || + if ((res= send_header_2(protocol)) || (count==0 && (search_categories(thd, 0, &categories_list, 0)<0 && (res= 1))) || - (res= send_variant_2_list(thd,&categories_list,true))) + (res= send_variant_2_list(protocol,&categories_list,true))) goto end; } } else if (count==1) { - if ((res= send_answer_1(thd,name->ptr(),"N", - description->ptr(), example->ptr()))) + if ((res= send_answer_1(protocol,name->ptr(),"N", + description->ptr(), example->ptr()))) goto end; } - else if((res= send_header_2(thd)) || - (res= send_variant_2_list(thd,&function_list,false)) || + else if((res= send_header_2(protocol)) || + (res= send_variant_2_list(protocol,&function_list,false)) || (search_categories(thd, mask, &categories_list, 0)<0 && (res=1)) || - (res= send_variant_2_list(thd,&categories_list,true))) + (res= send_variant_2_list(protocol,&categories_list,true))) { goto end; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 90568bfcc5e..f8c46c7cd41 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3010,11 +3010,11 @@ mysql_init_query(THD *thd) DBUG_VOID_RETURN; } + void mysql_init_select(LEX *lex) { SELECT_LEX *select_lex= lex->current_select->select_lex(); - DBUG_ASSERT(select_lex->linkage != GLOBAL_OPTIONS_TYPE); select_lex->init_select(); select_lex->master_unit()->select_limit= select_lex->select_limit= lex->thd->variables.select_limit; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9d6e6d75ade..704acc9c1c2 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -512,7 +512,8 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, sending any info on where clause. */ if (send_prep_stmt(stmt, fields.elements) || - send_fields(thd,fields,0) || send_item_params(stmt)) + thd->protocol_prep.send_fields(&fields,0) || + send_item_params(stmt)) DBUG_RETURN(1); DBUG_RETURN(0); } @@ -726,7 +727,9 @@ void mysql_stmt_execute(THD *thd, char *packet) mysql_delete(), mysql_update() and mysql_select() to not to have re-check on setup_* and other things .. */ + thd->protocol= &thd->protocol_prep; // Switch to binary protocol mysql_execute_command(stmt->thd); + thd->protocol= &thd->protocol_simple; // Use normal protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 23951cec29f..63cd192e539 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -928,14 +928,15 @@ int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1, int show_binlog_events(THD* thd) { + Protocol *protocol= thd->protocol; DBUG_ENTER("show_binlog_events"); List<Item> field_list; - const char* errmsg = 0; + const char *errmsg = 0; IO_CACHE log; File file = -1; Log_event::init_show_field_list(&field_list); - if (send_fields(thd, field_list, 1)) + if (protocol-> send_fields(&field_list, 1)) DBUG_RETURN(-1); if (mysql_bin_log.is_open()) @@ -983,7 +984,7 @@ int show_binlog_events(THD* thd) (ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,0)); ) { if (event_count >= limit_start && - ev->net_send(thd, linfo.log_file_name, pos)) + ev->net_send(protocol, linfo.log_file_name, pos)) { errmsg = "Net error"; delete ev; @@ -1029,28 +1030,30 @@ err: int show_binlog_info(THD* thd) { + Protocol *protocol= thd->protocol; DBUG_ENTER("show_binlog_info"); List<Item> field_list; field_list.push_back(new Item_empty_string("File", FN_REFLEN)); - field_list.push_back(new Item_empty_string("Position",20)); - field_list.push_back(new Item_empty_string("Binlog_do_db",20)); - field_list.push_back(new Item_empty_string("Binlog_ignore_db",20)); + field_list.push_back(new Item_return_int("Position",20, + MYSQL_TYPE_LONGLONG)); + field_list.push_back(new Item_empty_string("Binlog_do_db",255)); + field_list.push_back(new Item_empty_string("Binlog_ignore_db",255)); - if (send_fields(thd, field_list, 1)) + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); - String* packet = &thd->packet; - packet->length(0); + protocol->prepare_for_resend(); + if (mysql_bin_log.is_open()) { LOG_INFO li; mysql_bin_log.get_current_log(&li); int dir_len = dirname_length(li.log_file_name); - net_store_data(packet, li.log_file_name + dir_len); - net_store_data(packet, (longlong)li.pos); - net_store_data(packet, &binlog_do_db); - net_store_data(packet, &binlog_ignore_db); - if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length())) + protocol->store(li.log_file_name + dir_len); + protocol->store((ulonglong) li.pos); + protocol->store(&binlog_do_db); + protocol->store(&binlog_ignore_db); + if (protocol->write()) DBUG_RETURN(-1); } send_eof(thd); @@ -1079,6 +1082,8 @@ int show_binlogs(THD* thd) List<Item> field_list; String *packet = &thd->packet; uint length; + Protocol *protocol= thd->protocol; + DBUG_ENTER("show_binlogs"); if (!mysql_bin_log.is_open()) { @@ -1088,8 +1093,8 @@ int show_binlogs(THD* thd) } field_list.push_back(new Item_empty_string("Log_name", 255)); - if (send_fields(thd, field_list, 1)) - return 1; + if (protocol->send_fields(&field_list, 1)) + DBUG_RETURN(1); mysql_bin_log.lock_index(); index_file=mysql_bin_log.get_index_file(); @@ -1101,19 +1106,19 @@ int show_binlogs(THD* thd) int dir_len = dirname_length(fname); packet->length(0); /* The -1 is for removing newline from fname */ - net_store_data(packet, fname + dir_len, length-1-dir_len); - if (my_net_write(net, (char*) packet->ptr(), packet->length())) + protocol->store(fname + dir_len, length-1-dir_len); + if (protocol->write()) goto err; } mysql_bin_log.unlock_index(); send_eof(thd); - return 0; + DBUG_RETURN(0); err_with_msg: send_error(thd, ER_UNKNOWN_ERROR, errmsg); err: mysql_bin_log.unlock_index(); - return 1; + DBUG_RETURN(1); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5b8e2085982..683cc0925b6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7529,7 +7529,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, item_list.push_back(new Item_string(table->table_name, strlen(table->table_name), default_charset_info)); - item_list.push_back(new Item_string(join_type_str[tab->type],strlen(join_type_str[tab->type]),default_charset_info)); + item_list.push_back(new Item_string(join_type_str[tab->type], + strlen(join_type_str[tab->type]), + default_charset_info)); key_map bits; uint j; for (j=0,bits=tab->keys ; bits ; j++,bits>>=1) @@ -7587,9 +7589,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, item_list.push_back(item_null); item_list.push_back(item_null); } - sprintf(buff3,"%.0f",join->best_positions[i].records_read); - item_list.push_back(new Item_string(buff3,strlen(buff3), - default_charset_info)); + item_list.push_back(new Item_int((longlong) (ulonglong) + join->best_positions[i]. records_read, + 21)); my_bool key_read=table->key_read; if (tab->type == JT_NEXT && ((table->used_keys & ((key_map) 1 << tab->index)))) @@ -7645,6 +7647,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, DBUG_VOID_RETURN; } + int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) { DBUG_ENTER("mysql_explain_union"); @@ -7675,6 +7678,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) DBUG_RETURN(res); } + int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, select_result *result) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ebf5b210d6c..2826b44692e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -62,6 +62,7 @@ mysqld_show_dbs(THD *thd,const char *wild) char *end; List<char> files; char *file_name; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_dbs"); field->name=(char*) thd->alloc(20+ (wild ? (uint) strlen(wild)+4: 0)); @@ -71,13 +72,12 @@ mysqld_show_dbs(THD *thd,const char *wild) strxmov(end," (",wild,")",NullS); field_list.push_back(field); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1)) DBUG_RETURN(1); List_iterator_fast<char> it(files); - String *packet= &thd->packet; while ((file_name=it++)) { if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) || @@ -85,10 +85,9 @@ mysqld_show_dbs(THD *thd,const char *wild) thd->priv_user, file_name) || (grant_option && !check_grant_db(thd, file_name))) { - packet->length(0); - net_store_data(packet, thd->variables.convert_set, file_name); - if (my_net_write(&thd->net, (char*) packet->ptr(), - packet->length())) + protocol->prepare_for_resend(); + protocol->store(file_name); + if (protocol->write()) DBUG_RETURN(-1); } } @@ -105,29 +104,28 @@ int mysqld_show_open_tables(THD *thd,const char *wild) { List<Item> field_list; OPEN_TABLE_LIST *open_list; - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_open_tables"); field_list.push_back(new Item_empty_string("Database",NAME_LEN)); field_list.push_back(new Item_empty_string("Table",NAME_LEN)); - field_list.push_back(new Item_int("In_use",0, 4)); - field_list.push_back(new Item_int("Name_locked",0, 4)); + field_list.push_back(new Item_return_int("In_use", 1, MYSQL_TYPE_TINY)); + field_list.push_back(new Item_return_int("Name_locked", 4, MYSQL_TYPE_TINY)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); if (!(open_list=list_open_tables(thd,wild)) && thd->fatal_error) DBUG_RETURN(-1); - String *packet= &thd->packet; for (; open_list ; open_list=open_list->next) { - packet->length(0); - net_store_data(packet,convert, open_list->db); - net_store_data(packet,convert, open_list->table); - net_store_data(packet,open_list->in_use); - net_store_data(packet,open_list->locked); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->prepare_for_resend(); + protocol->store(open_list->db); + protocol->store(open_list->table); + protocol->store_tiny((longlong) open_list->in_use); + protocol->store_tiny((longlong) open_list->locked); + if (protocol->write()) { DBUG_RETURN(-1); } @@ -149,9 +147,11 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild) char path[FN_LEN],*end; List<char> files; char *file_name; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_tables"); - field->name=(char*) thd->alloc(20+(uint) strlen(db)+(wild ? (uint) strlen(wild)+4:0)); + field->name=(char*) thd->alloc(20+(uint) strlen(db)+ + (wild ? (uint) strlen(wild)+4:0)); end=strxmov(field->name,"Tables_in_",db,NullS); if (wild && wild[0]) strxmov(end," (",wild,")",NullS); @@ -159,17 +159,16 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild) (void) sprintf(path,"%s/%s",mysql_data_home,db); (void) unpack_dirname(path,path); field_list.push_back(field); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); if (mysql_find_files(thd,&files,db,path,wild,0)) DBUG_RETURN(-1); List_iterator_fast<char> it(files); - String *packet= &thd->packet; while ((file_name=it++)) { - packet->length(0); - net_store_data(packet, thd->variables.convert_set, file_name); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->prepare_for_resend(); + protocol->store(file_name); + if (protocol->write()) DBUG_RETURN(-1); } send_eof(thd); @@ -210,31 +209,32 @@ static struct show_table_type_st sys_table_types[]= int mysqld_show_table_types(THD *thd) { List<Item> field_list; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_table_types"); field_list.push_back(new Item_empty_string("Type",10)); field_list.push_back(new Item_empty_string("Support",10)); field_list.push_back(new Item_empty_string("Comment",80)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); - const char *default_type_name= ha_table_typelib.type_names[thd->variables.table_type]; + const char *default_type_name= + ha_table_typelib.type_names[thd->variables.table_type]; show_table_type_st *types; - String *packet= &thd->packet; for (types= sys_table_types; types->type; types++) { - packet->length(0); - net_store_data(packet, types->type); + protocol->prepare_for_resend(); + protocol->store(types->type); const char *option_name= show_comp_option_name[(int) *types->value]; if (*types->value == SHOW_OPTION_YES && !my_strcasecmp(system_charset_info, default_type_name, types->type)) option_name= "DEFAULT"; - net_store_data(packet, option_name); - net_store_data(packet, types->comment); - if (my_net_write(&thd->net, (char*) packet->ptr(), packet->length())) + protocol->store(option_name); + protocol->store(types->comment); + if (protocol->write()) DBUG_RETURN(-1); } send_eof(thd); @@ -279,24 +279,24 @@ static struct show_privileges_st sys_privileges[]= int mysqld_show_privileges(THD *thd) { List<Item> field_list; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_privileges"); field_list.push_back(new Item_empty_string("Privilege",10)); field_list.push_back(new Item_empty_string("Context",15)); field_list.push_back(new Item_empty_string("Comment",NAME_LEN)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); show_privileges_st *privilege= sys_privileges; - String *packet= &thd->packet; for (privilege= sys_privileges; privilege->privilege ; privilege++) { - packet->length(0); - net_store_data(packet,privilege->privilege); - net_store_data(packet,privilege->context); - net_store_data(packet,privilege->comment); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->prepare_for_resend(); + protocol->store(privilege->privilege); + protocol->store(privilege->context); + protocol->store(privilege->comment); + if (protocol->write()) DBUG_RETURN(-1); } send_eof(thd); @@ -343,14 +343,15 @@ static struct show_column_type_st sys_column_types[]= int mysqld_show_column_types(THD *thd) { List<Item> field_list; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_column_types"); field_list.push_back(new Item_empty_string("Type",30)); field_list.push_back(new Item_int("Size",(longlong) 1,21)); field_list.push_back(new Item_empty_string("Min_Value",20)); field_list.push_back(new Item_empty_string("Max_Value",20)); - field_list.push_back(new Item_int("Prec", 0,4)); - field_list.push_back(new Item_int("Scale", 0,4)); + field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT)); + field_list.push_back(new Item_return_int("Scale", 4, MYSQL_TYPE_SHORT)); field_list.push_back(new Item_empty_string("Nullable",4)); field_list.push_back(new Item_empty_string("Auto_Increment",4)); field_list.push_back(new Item_empty_string("Unsigned",4)); @@ -360,29 +361,28 @@ int mysqld_show_column_types(THD *thd) field_list.push_back(new Item_empty_string("Default",NAME_LEN)); field_list.push_back(new Item_empty_string("Comment",NAME_LEN)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); /* TODO: Change the loop to not use 'i' */ - String *packet= &thd->packet; for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++) { - packet->length(0); - net_store_data(packet,sys_column_types[i].type); - net_store_data(packet,(longlong)sys_column_types[i].size); - net_store_data(packet,sys_column_types[i].min_value); - net_store_data(packet,sys_column_types[i].max_value); - net_store_data(packet,(uint32)sys_column_types[i].precision); - net_store_data(packet,(uint32)sys_column_types[i].scale); - net_store_data(packet,sys_column_types[i].nullable); - net_store_data(packet,sys_column_types[i].auto_increment); - net_store_data(packet,sys_column_types[i].unsigned_attr); - net_store_data(packet,sys_column_types[i].zerofill); - net_store_data(packet,sys_column_types[i].searchable); - net_store_data(packet,sys_column_types[i].case_sensitivity); - net_store_data(packet,sys_column_types[i].default_value); - net_store_data(packet,sys_column_types[i].comment); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->prepare_for_resend(); + protocol->store(sys_column_types[i].type); + protocol->store((ulonglong) sys_column_types[i].size); + protocol->store(sys_column_types[i].min_value); + protocol->store(sys_column_types[i].max_value); + protocol->store_short((longlong) sys_column_types[i].precision); + protocol->store_short((longlong) sys_column_types[i].scale); + protocol->store(sys_column_types[i].nullable); + protocol->store(sys_column_types[i].auto_increment); + protocol->store(sys_column_types[i].unsigned_attr); + protocol->store(sys_column_types[i].zerofill); + protocol->store(sys_column_types[i].searchable); + protocol->store(sys_column_types[i].case_sensitivity); + protocol->store(sys_column_types[i].default_value); + protocol->store(sys_column_types[i].comment); + if (protocol->write()) DBUG_RETURN(-1); } send_eof(thd); @@ -477,8 +477,8 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) char path[FN_LEN]; char *file_name; TABLE *table; - String *packet= &thd->packet; - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; + TIME time; DBUG_ENTER("mysqld_extend_show_tables"); (void) sprintf(path,"%s/%s",mysql_data_home,db); @@ -514,7 +514,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) field_list.push_back(item=new Item_empty_string("Create_options",255)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Comment",80)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); if (mysql_find_files(thd,&files,db,path,wild,0)) @@ -524,70 +524,74 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) { TABLE_LIST table_list; bzero((char*) &table_list,sizeof(table_list)); - packet->length(0); - net_store_data(packet,convert, file_name); + protocol->prepare_for_resend(); + protocol->store(file_name); table_list.db=(char*) db; table_list.real_name= table_list.alias= file_name; if (!(table = open_ltable(thd, &table_list, TL_READ))) { for (uint i=0 ; i < field_list.elements ; i++) - net_store_null(packet); - net_store_data(packet,convert, thd->net.last_error); + protocol->store_null(); + protocol->store(thd->net.last_error); thd->net.last_error[0]=0; } else { struct tm tm_tmp; + const char *str; handler *file=table->file; file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK); - net_store_data(packet, convert, file->table_type()); - net_store_data(packet, convert, - (table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) ? - "Compressed" : - (table->db_options_in_use & HA_OPTION_PACK_RECORD) ? - "Dynamic" : "Fixed"); - net_store_data(packet, (longlong) file->records); - net_store_data(packet, (uint32) file->mean_rec_length); - net_store_data(packet, (longlong) file->data_file_length); + protocol->store(file->table_type()); + str= ((table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) ? + "Compressed" : + (table->db_options_in_use & HA_OPTION_PACK_RECORD) ? + "Dynamic" : "Fixed"); + protocol->store(str); + protocol->store((ulonglong) file->records); + protocol->store((ulonglong) file->mean_rec_length); + protocol->store((ulonglong) file->data_file_length); if (file->max_data_file_length) - net_store_data(packet, (longlong) file->max_data_file_length); + protocol->store((ulonglong) file->max_data_file_length); else - net_store_null(packet); - net_store_data(packet, (longlong) file->index_file_length); - net_store_data(packet, (longlong) file->delete_length); + protocol->store_null(); + protocol->store((ulonglong) file->index_file_length); + protocol->store((ulonglong) file->delete_length); if (table->found_next_number_field) { table->next_number_field=table->found_next_number_field; table->next_number_field->reset(); file->update_auto_increment(); - net_store_data(packet, table->next_number_field->val_int()); + protocol->store(table->next_number_field->val_int()); table->next_number_field=0; } else - net_store_null(packet); + protocol->store_null(); if (!file->create_time) - net_store_null(packet); + protocol->store_null(); else { localtime_r(&file->create_time,&tm_tmp); - net_store_data(packet, &tm_tmp); + localtime_to_TIME(&time, &tm_tmp); + protocol->store(&time); } if (!file->update_time) - net_store_null(packet); + protocol->store_null(); else { localtime_r(&file->update_time,&tm_tmp); - net_store_data(packet, &tm_tmp); + localtime_to_TIME(&time, &tm_tmp); + protocol->store(&time); } if (!file->check_time) - net_store_null(packet); + protocol->store_null(); else { localtime_r(&file->check_time,&tm_tmp); - net_store_data(packet, &tm_tmp); + localtime_to_TIME(&time, &tm_tmp); + protocol->store(&time); } - net_store_data(packet, convert, table->table_charset ? - table->table_charset->name : "default"); + str= (table->table_charset ? table->table_charset->name : "default"); + protocol->store(str); { char option_buff[350],*ptr; ptr=option_buff; @@ -624,19 +628,18 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE); ptr=strmov(ptr,buff); } - net_store_data(packet, convert, option_buff+1, - (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1)); + protocol->store(option_buff+1, + (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1)); } { char *comment=table->file->update_table_comment(table->comment); - net_store_data(packet, comment); + protocol->store(comment); if (comment != table->comment) my_free(comment,MYF(0)); } close_thread_tables(thd,0); } - if (my_net_write(&thd->net,(char*) packet->ptr(), - packet->length())) + if (protocol->write()) DBUG_RETURN(-1); } send_eof(thd); @@ -656,7 +659,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, handler *file; char tmp[MAX_FIELD_WIDTH]; Item *item; - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_fields"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); @@ -691,7 +694,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, (void) my_net_write(&thd->net,tmp,(uint) (pos-tmp)); } - if (send_fields(thd,field_list,0)) + if (protocol->send_fields(&field_list,0)) DBUG_RETURN(1); restore_record(table,2); // Get empty record @@ -714,19 +717,19 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, uint col_access; bool null_default_value=0; - packet->length(0); - net_store_data(packet,convert,field->field_name); + protocol->prepare_for_resend(); + protocol->store(field->field_name); field->sql_type(type); - net_store_data(packet,convert,type.ptr(),type.length()); + protocol->store(type.ptr(), type.length()); pos=(byte*) ((flags & NOT_NULL_FLAG) && field->type() != FIELD_TYPE_TIMESTAMP ? "" : "YES"); - net_store_data(packet,convert,(const char*) pos); + protocol->store((const char*) pos); pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" : (field->flags & UNIQUE_KEY_FLAG) ? "UNI" : (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":""); - net_store_data(packet,convert,(char*) pos); + protocol->store((char*) pos); if (field->type() == FIELD_TYPE_TIMESTAMP || field->unireg_check == Field::NEXT_NUMBER) @@ -735,17 +738,17 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, { // Not null by default type.set(tmp,sizeof(tmp),default_charset_info); field->val_str(&type,&type); - net_store_data(packet,convert,type.ptr(),type.length()); + protocol->store(type.ptr(),type.length()); } else if (field->maybe_null() || null_default_value) - net_store_null(packet); // Null as default + protocol->store_null(); // Null as default else - net_store_data(packet,convert,tmp,0); + protocol->store("",0); // empty string char *end=tmp; if (field->unireg_check == Field::NEXT_NUMBER) end=strmov(tmp,"auto_increment"); - net_store_data(packet,convert,tmp,(uint) (end-tmp)); + protocol->store(tmp,(uint) (end-tmp)); if (verbose) { @@ -760,10 +763,10 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, end=strmov(end,grant_types.type_names[bitnr]); } } - net_store_data(packet,convert, tmp+1,end == tmp ? 0 : (uint) (end-tmp-1)); - net_store_data(packet, field->comment.str,field->comment.length); + protocol->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1)); + protocol->store(field->comment.str, field->comment.length); } - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + if (protocol->write()) DBUG_RETURN(1); } } @@ -777,7 +780,9 @@ int mysqld_show_create(THD *thd, TABLE_LIST *table_list) { TABLE *table; - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; + char buff[2048]; + String buffer(buff, sizeof(buff), system_charset_info); DBUG_ENTER("mysqld_show_create"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); @@ -791,51 +796,17 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) List<Item> field_list; field_list.push_back(new Item_empty_string("Table",NAME_LEN)); - field_list.push_back(new Item_empty_string("Create Table",1024)); + field_list.push_back(new Item_empty_string("Create Table", MAX_BLOB_WIDTH)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list, 1)) + DBUG_RETURN(1); + protocol->prepare_for_resend(); + protocol->store(table->table_name); + if (store_create_info(thd, table, &buffer)) + DBUG_RETURN(-1); + protocol->store(buffer.ptr(), buffer.length()); + if (protocol->write()) DBUG_RETURN(1); - - String *packet = &thd->packet; - { - packet->length(0); - net_store_data(packet,convert, table->table_name); - /* - A hack - we need to reserve some space for the length before - we know what it is - let's assume that the length of create table - statement will fit into 3 bytes ( 16 MB max :-) ) - */ - ulong store_len_offset = packet->length(); - packet->length(store_len_offset + 4); - if (store_create_info(thd, table, packet)) - DBUG_RETURN(-1); - ulong create_len = packet->length() - store_len_offset - 4; - /* - Just in case somebody manages to create a table - with *that* much stuff in the definition - */ - if (create_len > 0x00ffffff) // better readable in HEX ... - { - /* - Just in case somebody manages to create a table - with *that* much stuff in the definition - */ - DBUG_RETURN(1); - } - - /* - Now we have to store the length in three bytes, even if it would fit - into fewer bytes, so we cannot use net_store_data() anymore, - and do it ourselves - */ - char* p = (char*)packet->ptr() + store_len_offset; - *p++ = (char) 253; // The client the length is stored using 3-bytes - int3store(p, create_len); - - // now we are in business :-) - if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length())) - DBUG_RETURN(1); - } send_eof(thd); DBUG_RETURN(0); } @@ -844,18 +815,19 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) int mysqld_show_logs(THD *thd) { + List<Item> field_list; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_logs"); - List<Item> field_list; field_list.push_back(new Item_empty_string("File",FN_REFLEN)); field_list.push_back(new Item_empty_string("Type",10)); field_list.push_back(new Item_empty_string("Status",10)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); #ifdef HAVE_BERKELEY_DB - if (!berkeley_skip && berkeley_show_logs(thd)) + if (!berkeley_skip && berkeley_show_logs(protocol)) DBUG_RETURN(-1); #endif @@ -869,7 +841,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) { TABLE *table; char buff[256]; - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_keys"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); @@ -883,15 +855,16 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) List<Item> field_list; Item *item; field_list.push_back(new Item_empty_string("Table",NAME_LEN)); - field_list.push_back(new Item_int("Non_unique",0,1)); + field_list.push_back(new Item_return_int("Non_unique",1, MYSQL_TYPE_TINY)); field_list.push_back(new Item_empty_string("Key_name",NAME_LEN)); - field_list.push_back(new Item_int("Seq_in_index",0,2)); + field_list.push_back(new Item_return_int("Seq_in_index",2, MYSQL_TYPE_TINY)); field_list.push_back(new Item_empty_string("Column_name",NAME_LEN)); field_list.push_back(item=new Item_empty_string("Collation",1)); item->maybe_null=1; field_list.push_back(item=new Item_int("Cardinality",0,21)); item->maybe_null=1; - field_list.push_back(item=new Item_int("Sub_part",0,3)); + field_list.push_back(item=new Item_return_int("Sub_part",3, + MYSQL_TYPE_TINY)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Packed",10)); item->maybe_null=1; @@ -900,7 +873,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) field_list.push_back(new Item_empty_string("Comment",255)); item->maybe_null=1; - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); String *packet= &thd->packet; @@ -909,54 +882,48 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) for (uint i=0 ; i < table->keys ; i++,key_info++) { KEY_PART_INFO *key_part= key_info->key_part; - char *end; + const char *str; for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) { - packet->length(0); - net_store_data(packet,convert,table->table_name); - net_store_data(packet,convert,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1); - net_store_data(packet,convert,key_info->name); - end=int10_to_str((long) (j+1),(char*) buff,10); - net_store_data(packet,convert,buff,(uint) (end-buff)); - net_store_data(packet,convert, - key_part->field ? key_part->field->field_name : - "?unknown field?"); + protocol->prepare_for_resend(); + protocol->store(table->table_name); + protocol->store_tiny((longlong) ((key_info->flags & HA_NOSAME) ? 0 :1)); + protocol->store(key_info->name); + protocol->store_tiny((longlong) (j+1)); + str=(key_part->field ? key_part->field->field_name : + "?unknown field?"); + protocol->store(str); if (table->file->index_flags(i) & HA_READ_ORDER) - net_store_data(packet,convert, - ((key_part->key_part_flag & HA_REVERSE_SORT) ? - "D" : "A"), 1); + protocol->store(((key_part->key_part_flag & HA_REVERSE_SORT) ? + "D" : "A"), 1); else - net_store_null(packet); /* purecov: inspected */ + protocol->store_null(); /* purecov: inspected */ KEY *key=table->key_info+i; if (key->rec_per_key[j]) { ha_rows records=(table->file->records / key->rec_per_key[j]); - end=longlong10_to_str((longlong) records, buff, 10); - net_store_data(packet,convert,buff,(uint) (end-buff)); + protocol->store((ulonglong) records); } else - net_store_null(packet); + protocol->store_null(); /* Check if we have a key part that only uses part of the field */ if (!key_part->field || key_part->length != table->field[key_part->fieldnr-1]->key_length()) - { - end=int10_to_str((long) key_part->length, buff,10); /* purecov: inspected */ - net_store_data(packet,convert,buff,(uint) (end-buff)); /* purecov: inspected */ - } + protocol->store_tiny((longlong) key_part->length); else - net_store_null(packet); - net_store_null(packet); // No pack_information yet + protocol->store_null(); + protocol->store_null(); // No pack_information yet /* Null flag */ uint flags= key_part->field ? key_part->field->flags : 0; char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES"); - net_store_data(packet,convert,(const char*) pos); - net_store_data(packet,convert,table->file->index_type(i)); + protocol->store((const char*) pos); + protocol->store(table->file->index_type(i)); /* Comment */ - net_store_data(packet,convert,""); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->store("", 0); + if (protocol->write()) DBUG_RETURN(1); /* purecov: inspected */ } } @@ -992,7 +959,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) field_list.push_back(new Item_field(field)); } restore_record(table,2); // Get empty record - if (send_fields(thd,field_list,2)) + if (thd->protocol->send_fields(&field_list,2)) DBUG_VOID_RETURN; VOID(net_flush(&thd->net)); DBUG_VOID_RETURN; @@ -1002,20 +969,20 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) int mysqld_dump_create_info(THD *thd, TABLE *table, int fd) { - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; + String *packet= protocol->storage_packet(); DBUG_ENTER("mysqld_dump_create_info"); DBUG_PRINT("enter",("table: %s",table->real_name)); - String *packet = &thd->packet; - packet->length(0); - if (store_create_info(thd,table,packet)) + protocol->prepare_for_resend(); + if (store_create_info(thd, table, packet)) DBUG_RETURN(-1); - if (convert) - convert->convert((char*) packet->ptr(), packet->length()); + if (protocol->convert) + protocol->convert->convert((char*) packet->ptr(), packet->length()); if (fd < 0) { - if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length())) + if (protocol->write()) DBUG_RETURN(-1); VOID(net_flush(&thd->net)); } @@ -1278,21 +1245,21 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) I_List<thread_info> thread_infos; ulong max_query_length= (verbose ? thd->variables.max_allowed_packet : PROCESS_LIST_WIDTH); - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_list_processes"); - field_list.push_back(new Item_int("Id",0,7)); + field_list.push_back(new Item_int("Id",0,11)); field_list.push_back(new Item_empty_string("User",16)); field_list.push_back(new Item_empty_string("Host",64)); field_list.push_back(field=new Item_empty_string("db",NAME_LEN)); field->maybe_null=1; field_list.push_back(new Item_empty_string("Command",16)); - field_list.push_back(new Item_empty_string("Time",7)); + field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG)); field_list.push_back(field=new Item_empty_string("State",30)); field->maybe_null=1; field_list.push_back(field=new Item_empty_string("Info",max_query_length)); field->maybe_null=1; - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_VOID_RETURN; VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list @@ -1358,37 +1325,26 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) VOID(pthread_mutex_unlock(&LOCK_thread_count)); thread_info *thd_info; - String *packet= &thd->packet; + time_t now= time(0); while ((thd_info=thread_infos.get())) { char buff[20],*end; - packet->length(0); - end=int10_to_str((long) thd_info->thread_id, buff,10); - net_store_data(packet,convert,buff,(uint) (end-buff)); - net_store_data(packet,convert,thd_info->user); - net_store_data(packet,convert,thd_info->host); - if (thd_info->db) - net_store_data(packet,convert,thd_info->db); - else - net_store_null(packet); + protocol->prepare_for_resend(); + protocol->store((ulonglong) thd_info->thread_id); + protocol->store(thd_info->user); + protocol->store(thd_info->host); + protocol->store(thd_info->db); if (thd_info->proc_info) - net_store_data(packet,convert,thd_info->proc_info); + protocol->store(thd_info->proc_info); else - net_store_data(packet,convert,command_name[thd_info->command]); + protocol->store(command_name[thd_info->command]); if (thd_info->start_time) - net_store_data(packet, - (uint32) (time((time_t*) 0) - thd_info->start_time)); - else - net_store_null(packet); - if (thd_info->state_info) - net_store_data(packet,convert,thd_info->state_info); - else - net_store_null(packet); - if (thd_info->query) - net_store_data(packet,convert,thd_info->query); + protocol->store((uint32) (now - thd_info->start_time)); else - net_store_null(packet); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->store_null(); + protocol->store(thd_info->state_info); + protocol->store(thd_info->query); + if (protocol->write()) break; /* purecov: inspected */ } send_eof(thd); @@ -1405,16 +1361,16 @@ int mysqld_show_charsets(THD *thd, const char *wild) char buff[8192]; String packet2(buff,sizeof(buff),default_charset_info); List<Item> field_list; - CONVERT *convert=thd->variables.convert_set; CHARSET_INFO **cs; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_charsets"); field_list.push_back(new Item_empty_string("Name",30)); - field_list.push_back(new Item_int("Id",0,7)); - field_list.push_back(new Item_int("strx_maxlen",0,7)); - field_list.push_back(new Item_int("mb_maxlen",0,7)); + field_list.push_back(new Item_return_int("Id",11, FIELD_TYPE_SHORT)); + field_list.push_back(new Item_return_int("strx_maxlen",3, FIELD_TYPE_TINY)); + field_list.push_back(new Item_return_int("mb_maxlen",3, FIELD_TYPE_TINY)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(1); for (cs=all_charsets ; cs < all_charsets+255 ; cs++ ) @@ -1424,14 +1380,13 @@ int mysqld_show_charsets(THD *thd, const char *wild) if (!(wild && wild[0] && wild_case_compare(system_charset_info,cs[0]->name,wild))) { - packet2.length(0); - net_store_data(&packet2,convert,cs[0]->name); - net_store_data(&packet2,(uint32) cs[0]->number); - net_store_data(&packet2,(uint32) cs[0]->strxfrm_multiply); - net_store_data(&packet2,(uint32) (cs[0]->mbmaxlen)); - - if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length())) - goto err; + protocol->prepare_for_resend(); + protocol->store(cs[0]->name); + protocol->store_short((longlong) cs[0]->number); + protocol->store_tiny((longlong) cs[0]->strxfrm_multiply); + protocol->store_tiny((longlong) cs[0]->mbmaxlen); + if (protocol->write()) + goto err; } } send_eof(thd); @@ -1445,15 +1400,14 @@ err: int mysqld_show(THD *thd, const char *wild, show_var_st *variables, enum enum_var_type value_type) { - char buff[8192]; - String packet2(buff,sizeof(buff), system_charset_info); + char buff[1024]; List<Item> field_list; - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show"); field_list.push_back(new Item_empty_string("Variable_name",30)); field_list.push_back(new Item_empty_string("Value",256)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); /* purecov: inspected */ /* pthread_mutex_lock(&THR_LOCK_keycache); */ @@ -1463,232 +1417,248 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, if (!(wild && wild[0] && wild_case_compare(system_charset_info, variables->name,wild))) { - packet2.length(0); - net_store_data(&packet2,convert,variables->name); + protocol->prepare_for_resend(); + protocol->store(variables->name); SHOW_TYPE show_type=variables->type; char *value=variables->value; + const char *pos, *end; + long nr; + if (show_type == SHOW_SYS) { show_type= ((sys_var*) value)->type(); value= (char*) ((sys_var*) value)->value_ptr(thd, value_type); } + pos= end= buff; switch (show_type) { case SHOW_LONG: case SHOW_LONG_CONST: - net_store_data(&packet2,(uint32) *(ulong*) value); + end= int10_to_str(*(long*) value, buff, 10); break; case SHOW_LONGLONG: - net_store_data(&packet2,(longlong) *(longlong*) value); + end= longlong10_to_str(*(longlong*) value, buff, 10); break; case SHOW_BOOL: - net_store_data(&packet2,(ulong) *(bool*) value ? "ON" : "OFF"); + end= strmov(buff, *(bool*) value ? "ON" : "OFF"); break; case SHOW_MY_BOOL: - net_store_data(&packet2,(ulong) *(my_bool*) value ? "ON" : "OFF"); + end= strmov(buff, *(my_bool*) value ? "ON" : "OFF"); break; case SHOW_INT_CONST: case SHOW_INT: - net_store_data(&packet2,(uint32) *(int*) value); + end= int10_to_str((long) *(uint32*) value, buff, 10); break; case SHOW_HAVE: { SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value; - net_store_data(&packet2, show_comp_option_name[(int) tmp]); + pos= show_comp_option_name[(int) tmp]; + end= strend(pos); break; } case SHOW_CHAR: - net_store_data(&packet2,convert, value); + pos= value; + end= strend(pos); break; case SHOW_STARTTIME: - net_store_data(&packet2,(uint32) (thd->query_start() - start_time)); + nr= (long) (thd->query_start() - start_time); + end= int10_to_str(nr, buff, 10); break; case SHOW_QUESTION: - net_store_data(&packet2,(uint32) thd->query_id); + end= int10_to_str((long) thd->query_id, buff, 10); break; case SHOW_RPL_STATUS: - net_store_data(&packet2, rpl_status_type[(int)rpl_status]); + end= int10_to_str((long) rpl_status_type[(int)rpl_status], buff, 10); break; case SHOW_SLAVE_RUNNING: { LOCK_ACTIVE_MI; - net_store_data(&packet2, (active_mi->slave_running && - active_mi->rli.slave_running) - ? "ON" : "OFF"); + end= strmov(buff, (active_mi->slave_running && + active_mi->rli.slave_running) ? "ON" : "OFF"); UNLOCK_ACTIVE_MI; break; } case SHOW_OPENTABLES: - net_store_data(&packet2,(uint32) cached_tables()); + end= int10_to_str((long) cached_tables(), buff, 10); break; case SHOW_CHAR_PTR: { - value= *(char**) value; - net_store_data(&packet2,convert, value ? value : ""); + if (!(pos= *(char**) value)) + pos= ""; + end= strend(pos); break; } #ifdef HAVE_OPENSSL /* First group - functions relying on CTX */ case SHOW_SSL_CTX_SESS_ACCEPT: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_accept(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_ACCEPT_GOOD: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept_good(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_accept_good(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_CONNECT_GOOD: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect_good(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_connect_good(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_CB_HITS: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_cb_hits(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_cb_hits(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_HITS: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_hits(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_hits(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_CACHE_FULL: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_cache_full(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_cache_full(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_MISSES: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_misses(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_misses(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_TIMEOUTS: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_)), + buff,10); break; case SHOW_SSL_CTX_SESS_NUMBER: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)), + buff,10); break; case SHOW_SSL_CTX_SESS_CONNECT: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_)), + buff,10); break; case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)), + buff,10); break; case SHOW_SSL_CTX_GET_VERIFY_MODE: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)), + buff,10); break; case SHOW_SSL_CTX_GET_VERIFY_DEPTH: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)), + buff,10); break; case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE: if (!ssl_acceptor_fd) { - net_store_data(&packet2,"NONE" ); + pos= "NONE"; + end= pos+4; break; } switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context_)) { case SSL_SESS_CACHE_OFF: - net_store_data(&packet2,"OFF" ); + pos= "OFF"; break; case SSL_SESS_CACHE_CLIENT: - net_store_data(&packet2,"CLIENT" ); + pos= "CLIENT"; break; case SSL_SESS_CACHE_SERVER: - net_store_data(&packet2,"SERVER" ); + pos= "SERVER"; break; case SSL_SESS_CACHE_BOTH: - net_store_data(&packet2,"BOTH" ); + pos= "BOTH"; break; case SSL_SESS_CACHE_NO_AUTO_CLEAR: - net_store_data(&packet2,"NO_AUTO_CLEAR" ); + pos= "NO_AUTO_CLEAR"; break; case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP: - net_store_data(&packet2,"NO_INTERNAL_LOOKUP" ); + pos= "NO_INTERNAL_LOOKUP"; break; default: - net_store_data(&packet2,"Unknown"); + pos= "Unknown"; break; } + pos= strend(pos); break; /* First group - functions relying on SSL */ case SHOW_SSL_GET_VERSION: - net_store_data(&packet2, thd->net.vio->ssl_ ? - SSL_get_version(thd->net.vio->ssl_) : ""); + pos= thd->net.vio->ssl_ ? SSL_get_version(thd->net.vio->ssl_) : ""; + end= strend(pos); break; case SHOW_SSL_SESSION_REUSED: - net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ? - SSL_session_reused(thd->net.vio->ssl_) : 0)); + end= int10_to_str((long) (thd->net.vio->ssl_ ? + SSL_session_reused(thd->net.vio->ssl_): + 0), buff, 10); break; case SHOW_SSL_GET_DEFAULT_TIMEOUT: - net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ? - SSL_get_default_timeout(thd->net.vio->ssl_):0)); + end= int10_to_str((long) (thd->net.vio->ssl_ ? + SSL_get_default_timeout(thd->net.vio->ssl_): + 0), buff, 10); break; case SHOW_SSL_GET_VERIFY_MODE: - net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ? - SSL_get_verify_mode(thd->net.vio->ssl_):0)); + end= int10_to_str((long) (thd->net.vio->ssl_ ? + SSL_get_verify_mode(thd->net.vio->ssl_): + 0), buff, 10); break; case SHOW_SSL_GET_VERIFY_DEPTH: - net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ? - SSL_get_verify_depth(thd->net.vio->ssl_):0)); + end= int10_to_str((long) (thd->net.vio->ssl_ ? + SSL_get_verify_depth(thd->net.vio->ssl_): + 0), buff, 10); break; case SHOW_SSL_GET_CIPHER: - net_store_data(&packet2, thd->net.vio->ssl_ ? - SSL_get_cipher(thd->net.vio->ssl_) : ""); + pos= thd->net.vio->ssl_ ? SSL_get_cipher(thd->net.vio->ssl_) : ""; + end= strend(pos); break; case SHOW_SSL_GET_CIPHER_LIST: if (thd->net.vio->ssl_) { - char buf[1024], *pos; - pos=buf; + char *to= buff; for (int i=0 ; i++ ;) { - const char *p=SSL_get_cipher_list(thd->net.vio->ssl_,i); + const char *p= SSL_get_cipher_list(thd->net.vio->ssl_,i); if (p == NULL) break; - pos=strmov(pos, p); - *pos++= ':'; + to= strmov(to, p); + *to++= ':'; } - if (pos != buf) - pos--; // Remove last ':' - *pos=0; - net_store_data(&packet2, buf); + if (to != buff) + to--; // Remove last ':' + end= to; } - else - net_store_data(&packet2, ""); break; #endif /* HAVE_OPENSSL */ case SHOW_UNDEF: // Show never happen case SHOW_SYS: - net_store_data(&packet2, ""); // Safety - break; + break; // Return empty string } - if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length())) + if (protocol->store(pos, (uint32) (end - pos)) || + protocol->write()) goto err; /* purecov: inspected */ } } diff --git a/sql/sql_string.h b/sql/sql_string.h index dde67b11d50..d7447dd6ed6 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -255,4 +255,29 @@ public: void qs_append(double d); void qs_append(double *d); void qs_append(const char &c); + + /* Inline (general) functions used by the protocol functions */ + + inline char *prep_append(uint32 arg_length, uint32 step_alloc) + { + uint32 new_length= arg_length + str_length; + if (new_length > Alloced_length) + { + if (realloc(new_length + step_alloc)) + return 0; + } + uint32 old_length= str_length; + str_length+= arg_length; + return Ptr+ old_length; /* Area to use */ + } + + inline bool append(const char *s, uint32 arg_length, uint32 step_alloc) + { + uint32 new_length= arg_length + str_length; + if (new_length > Alloced_length && realloc(new_length + step_alloc)) + return TRUE; + memcpy(Ptr+str_length, s, arg_length); + str_length+= arg_length; + return FALSE; + } }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d343ccd39f5..1ab84531e40 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1017,20 +1017,18 @@ bool close_cached_table(THD *thd,TABLE *table) DBUG_RETURN(result); } -static int send_check_errmsg(THD* thd, TABLE_LIST* table, +static int send_check_errmsg(THD *thd, TABLE_LIST* table, const char* operator_name, const char* errmsg) { - - String* packet = &thd->packet; - packet->length(0); - net_store_data(packet, table->alias); - net_store_data(packet, (char*)operator_name); - net_store_data(packet, "error"); - net_store_data(packet, errmsg); + Protocol *protocol= thd->protocol; + protocol->prepare_for_resend(); + protocol->store(table->alias); + protocol->store((char*) operator_name); + protocol->store("error", 5); + protocol->store(errmsg); thd->net.last_error[0]=0; - if (my_net_write(&thd->net, (char*) thd->packet.ptr(), - packet->length())) + if (protocol->write()) return -1; return 1; } @@ -1176,8 +1174,8 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, { TABLE_LIST *table; List<Item> field_list; - Item* item; - String* packet = &thd->packet; + Item *item; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysql_admin_table"); field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2)); @@ -1188,7 +1186,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, item->maybe_null = 1; field_list.push_back(item = new Item_empty_string("Msg_text", 255)); item->maybe_null = 1; - if (send_fields(thd, field_list, 1)) + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); for (table = tables; table; table = table->next) @@ -1201,7 +1199,8 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, thd->open_options|= extra_open_options; table->table = open_ltable(thd, table, lock_type); thd->open_options&= ~extra_open_options; - packet->length(0); + protocol->prepare_for_resend(); + if (prepare_func) { switch ((*prepare_func)(thd, table, check_opt)) { @@ -1214,30 +1213,30 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, if (!table->table) { const char *err_msg; - net_store_data(packet, table_name); - net_store_data(packet, operator_name); - net_store_data(packet, "error"); + protocol->prepare_for_resend(); + protocol->store(table_name); + protocol->store(operator_name); + protocol->store("error",5); if (!(err_msg=thd->net.last_error)) err_msg=ER(ER_CHECK_NO_SUCH_TABLE); - net_store_data(packet, err_msg); + protocol->store(err_msg); thd->net.last_error[0]=0; - if (my_net_write(&thd->net, (char*) thd->packet.ptr(), - packet->length())) + if (protocol->write()) goto err; continue; } if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify) { char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE]; - net_store_data(packet, table_name); - net_store_data(packet, operator_name); - net_store_data(packet, "error"); + protocol->prepare_for_resend(); + protocol->store(table_name); + protocol->store(operator_name); + protocol->store("error", 5); sprintf(buff, ER(ER_OPEN_AS_READONLY), table_name); - net_store_data(packet, buff); + protocol->store(buff); close_thread_tables(thd); table->table=0; // For query cache - if (my_net_write(&thd->net, (char*) thd->packet.ptr(), - packet->length())) + if (protocol->write()) goto err; continue; } @@ -1265,50 +1264,50 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, } int result_code = (table->table->file->*operator_func)(thd, check_opt); - packet->length(0); - net_store_data(packet, table_name); - net_store_data(packet, operator_name); + protocol->prepare_for_resend(); + protocol->store(table_name); + protocol->store(operator_name); switch (result_code) { case HA_ADMIN_NOT_IMPLEMENTED: { char buf[ERRMSGSIZE+20]; - my_snprintf(buf, ERRMSGSIZE, - ER(ER_CHECK_NOT_IMPLEMENTED), operator_name); - net_store_data(packet, "error"); - net_store_data(packet, buf); + uint length=my_snprintf(buf, ERRMSGSIZE, + ER(ER_CHECK_NOT_IMPLEMENTED), operator_name); + protocol->store("error", 5); + protocol->store(buf, length); } break; case HA_ADMIN_OK: - net_store_data(packet, "status"); - net_store_data(packet, "OK"); + protocol->store("status", 6); + protocol->store("OK",2); break; case HA_ADMIN_FAILED: - net_store_data(packet, "status"); - net_store_data(packet, "Operation failed"); + protocol->store("status", 6); + protocol->store("Operation failed",16); break; case HA_ADMIN_ALREADY_DONE: - net_store_data(packet, "status"); - net_store_data(packet, "Table is already up to date"); + protocol->store("status", 6); + protocol->store("Table is already up to date", 27); break; case HA_ADMIN_CORRUPT: - net_store_data(packet, "error"); - net_store_data(packet, "Corrupt"); + protocol->store("error", 5); + protocol->store("Corrupt", 8); fatal_error=1; break; case HA_ADMIN_INVALID: - net_store_data(packet, "error"); - net_store_data(packet, "Invalid argument"); + protocol->store("error", 5); + protocol->store("Invalid argument",16); break; default: // Probably HA_ADMIN_INTERNAL_ERROR - net_store_data(packet, "error"); - net_store_data(packet, "Unknown - internal error during operation"); + protocol->store("error", 5); + protocol->store("Unknown - internal error during operation", 41); fatal_error=1; break; } @@ -1325,8 +1324,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, } close_thread_tables(thd); table->table=0; // For query cache - if (my_net_write(&thd->net, (char*) packet->ptr(), - packet->length())) + if (protocol->write()) goto err; } diff --git a/sql/structs.h b/sql/structs.h index 7873de4db63..604be6fcc6e 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -113,7 +113,8 @@ enum timestamp_type { TIMESTAMP_NONE, TIMESTAMP_DATE, TIMESTAMP_FULL, TIMESTAMP_TIME }; typedef struct st_time { - uint year,month,day,hour,minute,second,second_part; + uint year,month,day,hour,minute,second; + ulong second_part; bool neg; timestamp_type time_type; } TIME; diff --git a/sql/time.cc b/sql/time.cc index 0811b896bfc..282075df9eb 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -724,3 +724,20 @@ bool str_to_time(const char *str,uint length,TIME *l_time) } return 0; } + + +/* + Convert a system time structure to TIME +*/ + +void localtime_to_TIME(TIME *to, struct tm *from) +{ + to->neg=0; + to->second_part=0; + to->year= (int) ((from->tm_year+1900) % 10000); + to->month= (int) from->tm_mon+1; + to->day= (int) from->tm_mday; + to->hour= (int) from->tm_hour; + to->minute= (int) from->tm_min; + to->second= (int) from->tm_sec; +} diff --git a/tests/fork_big2.pl b/tests/fork_big2.pl new file mode 100644 index 00000000000..b552b95ba6b --- /dev/null +++ b/tests/fork_big2.pl @@ -0,0 +1,705 @@ +#!/usr/bin/perl -w +# +# This is a test with uses many processes to test a MySQL server. +# +# Tested a lot with: --threads=30 + +$opt_loop_count=500000; # Change this to make test harder/easier + +##################### Standard benchmark inits ############################## + +use DBI; +use Getopt::Long; +use Benchmark; + +package main; + +$opt_skip_create=$opt_skip_in=$opt_verbose=$opt_fast_insert= +$opt_lock_tables=$opt_debug=$opt_skip_drop=$opt_fast=$opt_force=0; +$opt_thread_factor=1;
+$opt_insert=1;
+$opt_select=6;$opt_join=4;
+$opt_select_count=$opt_join_count=0;
+$opt_update=1;$opt_delete=0;
+$opt_flush=$opt_check=$opt_repair=$opt_alter=0;
+$opt_join_range=100;
+$opt_time=0; +$opt_host=$opt_user=$opt_password=""; $opt_db="test"; + +GetOptions("host=s","db=s","user=s","password=s","loop-count=i","skip-create","skip-in","skip-drop",
+ "verbose","fast-insert","lock-tables","debug","fast","force","thread-factor=i",
+ "insert=i", "select=i", "join=i", "select-count=i", "join-count=i", "update=i", "delete=i",
+ "flush=i", "check=i", "repair=i", "alter=i", "max-join_range=i", "time=i") || die "Aborted"; +$opt_verbose=$opt_debug=$opt_lock_tables=$opt_fast_insert=$opt_fast=$opt_skip_in=$opt_force=undef; # Ignore warnings from these + +print "Test of multiple connections that test the following things:\n"; +print "insert, select, delete, update, alter, check, repair and flush\n"; + +@testtables = ( ["bench_f31", ""], + ["bench_f32", "row_format=fixed"], + ["bench_f33", "delay_key_write=1"], + ["bench_f34", "checksum=1"], + ["bench_f35", "delay_key_write=1"]); +$abort_table="bench_f39"; + +$numtables = $#testtables+1; +srand 100; # Make random numbers repeatable + +#### +#### Start timeing and start test +####
+
+$opt_insert*=$opt_thread_factor; +$opt_select*=$opt_thread_factor;
+$opt_join*=$opt_thread_factor;
+$opt_select_count*=$opt_thread_factor;
+$opt_join_count*=$opt_thread_factor;
+$opt_update*=$opt_thread_factor;
+$opt_delete*=$opt_thread_factor;
+
+if ($opt_time == 0 && $opt_insert == 0)
+{
+ $opt_insert=1;
+}
+ +$start_time=new Benchmark; +$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; +if (!$opt_skip_create) +{ + my $table_def; + foreach $table_def (@testtables) + { + my ($table,$extra)= ($table_def->[0], $table_def->[1]); + print "Creating table $table in database $opt_db\n"; + $dbh->do("drop table if exists $table"); + $dbh->do("create table $table". + " (id int(6) not null auto_increment,". + " info varchar(32)," . + " marker timestamp," . + " flag int not null," . + " primary key(id)) $extra") + + or die $DBI::errstr; + # One row in the table will make future tests easier + $dbh->do("insert into $table (id) values (null)") + or die $DBI::errstr; + } + # Create the table we use to signal that we should end the test + $dbh->do("drop table if exists $abort_table"); + $dbh->do("create table $abort_table (id int(6) not null) type=heap") || + die $DBI::errstr; +} + +$dbh->do("delete from $abort_table"); +$dbh->disconnect; $dbh=0; # Close handler +$|= 1; # Autoflush + +#### +#### Start the tests +#### +if ($opt_time != 0)
+{
+ test_abort() if (($pid=fork()) == 0); $work{$pid}="abort";
+} +for ($i=0 ; $i < $opt_insert ; $i ++) +{ + test_insert() if (($pid=fork()) == 0); $work{$pid}="insert"; +}
+$threads=$i; +for ($i=0 ; $i < $opt_select ; $i ++)
+{
+ test_select() if (($pid=fork()) == 0); $work{$pid}="select";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_join ; $i ++)
+{
+ test_join() if (($pid=fork()) == 0); $work{$pid}="join";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_select_count ; $i ++) +{ + test_select_count() if (($pid=fork()) == 0); $work{$pid}="select_count"; +} +$threads+=$i;
+for ($i=0 ; $i < $opt_join_count ; $i ++)
+{
+ test_join_count() if (($pid=fork()) == 0); $work{$pid}="join_count";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_update ; $i ++)
+{
+ test_update() if (($pid=fork()) == 0); $work{$pid}="update";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_delete ; $i ++)
+{
+ test_delete() if (($pid=fork()) == 0); $work{$pid}="delete";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_flush ; $i ++)
+{
+ test_flush() if (($pid=fork()) == 0); $work{$pid}="flush";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_check ; $i ++)
+{
+ test_check() if (($pid=fork()) == 0); $work{$pid}="check";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_repair ; $i ++)
+{
+ test_repair() if (($pid=fork()) == 0); $work{$pid}="repair";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_alter ; $i ++)
+{
+ test_alter() if (($pid=fork()) == 0); $work{$pid}="alter";
+}
+$threads+=$i;
+
+print "Started $threads threads\n"; + +$errors=0; +$running_insert_threads=$opt_insert; +while (($pid=wait()) != -1) +{ + $ret=$?/256; + print "thread '" . $work{$pid} . "' finished with exit code $ret\n";
+ if ($opt_time == 0)
+ { + if ($work{$pid} =~ /^insert/) + { + if (!--$running_insert_threads) + {
+
+ # Time to stop other threads + signal_abort(); + }
+ } + } + $errors++ if ($ret != 0); +} + +# +# Cleanup +# + +if (!$opt_skip_drop && !$errors) +{ + my $table_def; + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $dbh->do("drop table $abort_table"); + foreach $table_def (@testtables) + { + $dbh->do("drop table " . $table_def->[0]); + } + $dbh->disconnect; $dbh=0; # Close handler +} + +print ($errors ? "Test failed\n" :"Test ok\n"); +$end_time=new Benchmark; +print "Total time: " . + timestr(timediff($end_time, $start_time),"noc") . "\n"; + +exit(0); + +#
+# Sleep and then abort other threads
+#
+
+sub test_abort
+{
+ sleep($opt_time);
+ signal_abort();
+ exit(0);
+}
+
+ +# +# Insert records in the table +# + +sub test_insert +{ + my ($from_table,$to_table)= @_; + my ($dbh,$i,$j,$count,$table_def,$table); + + if (!defined($from_table)) + { + $from_table=0; $to_table=$numtables-1; + } + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + for ($i=$count=0 ; $i < $opt_loop_count; $i++) + { + for ($j= $from_table ; $j <= $to_table ; $j++) + { + my ($table)= ($testtables[$j]->[0]); + $dbh->do("insert into $table values (NULL,'This is entry $i','',0)") || die "Got error on insert: $DBI::errstr\n"; + $count++; + } + } + $dbh->disconnect; $dbh=0; + print "Test_insert: Inserted $count rows\n"; + exit(0); +} + + +# +# select records +# Do continously select over all tables as long as there is changed +# rows in the table +# + +sub test_select +{ + my ($dbh, $i, $j, $count, $loop); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $count_query=make_count_query($numtables); + $count=0; + $loop=9999; + + $i=0; + while (($i++ % 100) || !test_if_abort($dbh)) + { + if ($loop++ >= 100) + { + $loop=0; + $row_counts=simple_query($dbh, $count_query); + } + for ($j=0 ; $j < $numtables ; $j++) + { + my ($id)= int rand $row_counts->[$j]; + my ($table)= $testtables[$j]->[0]; + simple_query($dbh, "select id,info from $table where id=$id"); + $count++; + } + } + $dbh->disconnect; $dbh=0; + print "Test_select: Executed $count selects\n"; + exit(0); +} + +# +# Do big select count(distinct..) over the table +# + +sub test_select_count +{ + my ($dbh, $i, $j, $count, $loop); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $count=0; + $i=0; + while (!test_if_abort($dbh)) + { + for ($j=0 ; $j < $numtables ; $j++) + { + my ($table)= $testtables[$j]->[0]; + simple_query($dbh, "select count(distinct marker),count(distinct id),count(distinct info) from $table"); + $count++; + } + sleep(20); # This query is quite slow + } + $dbh->disconnect; $dbh=0; + print "Test_select: Executed $count select count(distinct) queries\n"; + exit(0); +} + +# +# select records +# Do continously joins between the first and second table +# + +sub test_join +{ + my ($dbh, $i, $j, $count, $loop); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $count_query=make_count_query($numtables); + $count=0; + $loop=9999; + + $i=0; + while (($i++ % 100) || !test_if_abort($dbh)) + { + if ($loop++ >= 100) + { + $loop=0; + $row_counts=simple_query($dbh, $count_query); + } + for ($j=0 ; $j < $numtables-1 ; $j++) + { + my ($id)= int rand $row_counts->[$j]; + my ($t1,$t2)= ($testtables[$j]->[0],$testtables[$j+1]->[0]); + simple_query($dbh, "select $t1.id,$t2.info from $t1, $t2 where $t1.id=$t2.id and $t1.id=$id"); + $count++; + } + } + $dbh->disconnect; $dbh=0; + print "Test_join: Executed $count joins\n"; + exit(0); +}
+
+#
+# select records
+# Do continously joins between the first and second for range and count selected rows
+#
+
+sub test_join_count
+{
+ my ($dbh, $i, $j, $count, $loop);
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+
+ $count_query=make_count_query($numtables);
+ $count=0;
+ $loop=9999;
+ $sum=0;
+
+ srand();
+
+ $i=0;
+ while (($i++ % 10) || !test_if_abort($dbh))
+ {
+ if ($loop++ >= 10)
+ {
+ $loop=0;
+ $row_counts=simple_query($dbh, $count_query);
+ }
+ for ($j=0 ; $j < $numtables-1 ; $j++)
+ {
+ my ($id1)= int rand $row_counts->[$j];
+ my ($id2)= int rand $row_counts->[$j];
+ if ($id1 > $id2)
+ {
+ my $id0=$id1; $id1=$id2; $id2=$id0;
+ if ($id2-$id1 > $opt_join_range)
+ {
+ $id2=$id1+$opt_join_range;
+ }
+ }
+ my ($t1,$t2)= ($testtables[$j]->[0],$testtables[$j+1]->[0]);
+ $row=simple_query($dbh, "select count(*) from $t1, $t2 where $t1.id=$t2.id and $t1.id between $id1 and $id2");
+ $sum+=$row->[0];
+ $count++;
+ }
+ }
+ $dbh->disconnect; $dbh=0;
+ print "Test_join_count: Executed $count joins: total $sum rows\n";
+ exit(0);
+}
+ + +# +# Delete 1-5 rows from the first 2 tables. +# Test ends when the number of rows for table 3 didn't change during +# one loop +# + +sub test_delete +{ + my ($dbh, $i,$j, $row_counts, $count_query, $table_count, $count); + + $table_count=2; + $count=0; + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $count_query=make_count_query($table_count+1); + + sleep(5); # Give time to insert some rows + $i=0; + while (($i++ % 10) || !test_if_abort($dbh)) + { + sleep(1); + $row_counts=simple_query($dbh, $count_query); + + for ($j=0 ; $j < $table_count ; $j++) + { + my ($id)= int rand $row_counts->[$j]; + my ($table)= $testtables[$j]->[0]; + $dbh->do("delete from $table where id >= $id-2 and id <= $id +2") || die "Got error on delete from $table: $DBI::errstr\n"; + $count++; + } + } + $dbh->disconnect; $dbh=0; + print "Test_delete: Executed $count deletes\n"; + exit(0); +} + +# +# Update the flag for table 2 and 3 +# Will abort after a while when table1 doesn't change max value +# + +sub test_update +{ + my ($dbh, $i, $j, $row_counts, $count_query, $count, $loop); + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $count_query=make_count_query(3); + $loop=9999; + $count=0; + + sleep(5); # Give time to insert some rows + $i=0; + while (($i++ % 100) || !test_if_abort($dbh)) + { + if ($loop++ >= 100) + { + $loop=0; + $row_counts=simple_query($dbh, $count_query); + } + + for ($j=1 ; $j <= 2 ; $j++) + { + my ($id)= int rand $row_counts->[$j]; + my ($table)= $testtables[$j]->[0]; + # Fix to not change the same rows as the above delete + $id= ($id + $count) % $row_counts->[$j]; + + $dbh->do("update $table set flag=flag+1 where id >= $id-2 and id <= $id +2") || die "Got error on update of $table: $DBI::errstr\n"; + $count++; + } + } + $dbh->disconnect; $dbh=0; + print "Test_update: Executed $count updates\n"; + exit(0); +} + + +# +# Run a check on all tables except the last one +# (The last one is not checked to put pressure on the key cache) +# + +sub test_check +{ + my ($dbh, $row, $i, $j, $type, $table); + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $type= "check"; + for ($i=$j=0 ; !test_if_abort($dbh) ; $i++) + { + sleep(1000); + $table=$testtables[$j]->[0]; + $sth=$dbh->prepare("$type table $table") || die "Got error on prepare: $DBI::errstr\n"; + $sth->execute || die $DBI::errstr; + + while (($row=$sth->fetchrow_arrayref)) + { + if ($row->[3] ne "OK") + { + print "Got error " . $row->[3] . " when doing $type on $table\n"; + exit(1); + } + } + if (++$j == $numtables-1) + { + $j=0; + } + } + $dbh->disconnect; $dbh=0; + print "test_check: Executed $i checks\n"; + exit(0); +} + +# +# Do a repair on the first table once in a while +# + +sub test_repair +{ + my ($dbh, $row, $i, $type, $table); + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $type= "repair"; + for ($i=0 ; !test_if_abort($dbh) ; $i++) + { + sleep(2000); + $table=$testtables[0]->[0]; + $sth=$dbh->prepare("$type table $table") || die "Got error on prepare: $DBI::errstr\n"; + $sth->execute || die $DBI::errstr; + + while (($row=$sth->fetchrow_arrayref)) + { + if ($row->[3] ne "OK") + { + print "Got error " . $row->[3] . " when doing $type on $table\n"; + exit(1); + } + } + } + $dbh->disconnect; $dbh=0; + print "test_repair: Executed $i repairs\n"; + exit(0); +} + +# +# Do a flush tables on table 3 and 4 once in a while +# + +sub test_flush +{ + my ($dbh,$count,$tables); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $tables=$testtables[2]->[0] . "," . $testtables[3]->[0]; + + $count=0; + while (!test_if_abort($dbh)) + { + sleep(3000); + $dbh->do("flush tables $tables") || + die "Got error on flush $DBI::errstr\n"; + $count++; + } + $dbh->disconnect; $dbh=0; + print "flush: Executed $count flushs\n"; + exit(0); +} + + +# +# Test all tables in a database +# + +sub test_database +{ + my ($database) = @_; + my ($dbh, $row, $i, $type, $tables); + $dbh = DBI->connect("DBI:mysql:$database:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $tables= join(',',$dbh->func('_ListTables')); + $type= "check"; + for ($i=0 ; !test_if_abort($dbh) ; $i++) + { + sleep(120); + $sth=$dbh->prepare("$type table $tables") || die "Got error on prepare: $DBI::errstr\n"; + $sth->execute || die $DBI::errstr; + + while (($row=$sth->fetchrow_arrayref)) + { + if ($row->[3] ne "OK") + { + print "Got error " . $row->[2] . " " . $row->[3] . " when doing $type on " . $row->[0] . "\n"; + exit(1); + } + } + } + $dbh->disconnect; $dbh=0; + print "test_check: Executed $i checks\n"; + exit(0); +} + +# +# Test ALTER TABLE on the second table +# + +sub test_alter +{ + my ($dbh, $row, $i, $type, $table); + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + for ($i=0 ; !test_if_abort($dbh) ; $i++) + { + sleep(100); + $table=$testtables[1]->[0]; + $sth=$dbh->prepare("ALTER table $table modify info char(32)") || die "Got error on prepare: $DBI::errstr\n"; + $sth->execute || die $DBI::errstr; + } + $dbh->disconnect; $dbh=0; + print "test_alter: Executed $i ALTER TABLE\n"; + exit(0); +} + + +# +# Help functions +# + +sub signal_abort +{ + my ($dbh); + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $dbh->do("insert into $abort_table values(1)") || die $DBI::errstr; + $dbh->disconnect; $dbh=0; +} + + +sub test_if_abort() +{ + my ($dbh)=@_; + $row=simple_query($dbh,"select * from $opt_db.$abort_table"); + return (defined($row) && defined($row->[0]) != 0) ? 1 : 0; +} + + +sub make_count_query +{ + my ($table_count)= @_; + my ($tables, $count_query, $i, $tables_def); + $tables=""; + $count_query="select high_priority "; + $table_count--; + for ($i=0 ; $i < $table_count ; $i++) + { + my ($table_def)= $testtables[$i]; + $tables.=$table_def->[0] . ","; + $count_query.= "max(" . $table_def->[0] . ".id),"; + } + $table_def=$testtables[$table_count]; + $tables.=$table_def->[0]; + $count_query.= "max(" . $table_def->[0] . ".id) from $tables"; + return $count_query; +} + +sub simple_query() +{ + my ($dbh, $query)= @_; + my ($sth,$row); + + $sth=$dbh->prepare($query) || die "Got error on '$query': " . $dbh->errstr . "\n"; + $sth->execute || die "Got error on '$query': " . $dbh->errstr . "\n"; + $row= $sth->fetchrow_arrayref(); + $sth=0; + return $row; +} |