rename of net_pkg.cc to protocol.cc

Class for sending data from server to client (Protocol)
This handles both the old ( <= 4.0 ) protocol and then new binary protocol that is used for prepared statements.
This commit is contained in:
monty@mashka.mysql.fi 2002-12-11 09:17:51 +02:00
parent 8762e83485
commit d3eb993a27
48 changed files with 2877 additions and 1659 deletions

View file

@ -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;

View file

@ -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 \

View file

@ -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

View file

@ -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

View file

@ -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 \

View file

@ -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());
}
@ -1071,6 +1066,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)
{
@ -1283,6 +1282,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)))
{
@ -1308,6 +1308,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;
@ -1533,6 +1539,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;
@ -1767,6 +1779,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;
@ -1979,6 +1996,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;
@ -2293,6 +2316,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)
@ -2490,6 +2519,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)
{
@ -2812,6 +2846,7 @@ String *Field_timestamp::val_str(String *val_buffer,
return val_buffer;
}
bool Field_timestamp::get_date(TIME *ltime, bool fuzzydate)
{
long temp;
@ -2851,6 +2886,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;
@ -2869,6 +2913,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
@ -3059,6 +3104,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;
@ -3961,19 +4017,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;
}
@ -4178,6 +4230,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
@ -4453,7 +4527,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

View file

@ -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; }

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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,6 +625,18 @@ void Item::init_make_field(Send_field *tmp_field,
tmp_field->flags |= UNSIGNED_FLAG;
}
void Item::make_field(Send_field *tmp_field)
{
init_make_field(tmp_field, field_type());
}
enum_field_types Item::field_type() const
{
return ((result_type() == STRING_RESULT) ? FIELD_TYPE_VAR_STRING :
(result_type() == INT_RESULT) ? FIELD_TYPE_LONGLONG :
FIELD_TYPE_DOUBLE);
}
/* ARGSUSED */
void Item_field::make_field(Send_field *tmp_field)
{
@ -638,58 +645,6 @@ void Item_field::make_field(Send_field *tmp_field)
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)
{
init_make_field(tmp_field,FIELD_TYPE_DATETIME);
}
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)
{
init_make_field(tmp_field, ((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)
{
init_make_field(tmp_field,FIELD_TYPE_DOUBLE);
}
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);
}
/*

View file

@ -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); }
};
@ -374,8 +387,8 @@ public:
longlong val_int() { return strtoll(str_value.ptr(),(char**) 0,10); }
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); }
@ -392,7 +405,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();
@ -412,7 +424,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
@ -422,6 +434,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:
@ -432,8 +458,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; }
};
@ -488,13 +514,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);
};
@ -544,6 +571,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()

View file

@ -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;

View file

@ -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);

View file

@ -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)

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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,

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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)
{

View file

@ -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 __attribute__((unused)))
@ -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 __attribute__((unused)))
@ -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) { str_value.copy(str,length, thd_charset()); }

983
sql/protocol.cc Normal file
View file

@ -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);
}

131
sql/protocol.h Normal file
View file

@ -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);

View file

@ -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);

View file

@ -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);
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
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);
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*)packet.ptr(),
packet.length(), 0))
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);
}

View file

@ -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;

View file

@ -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
****************************************************************************/

View file

@ -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()

View file

@ -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

View file

@ -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);
}

View file

@ -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;

View file

@ -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))

View file

@ -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;
}

View file

@ -3012,11 +3012,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;

View file

@ -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);

View file

@ -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);
}

View file

@ -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)
{

File diff suppressed because it is too large Load diff

View file

@ -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;
}
};

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

705
tests/fork_big2.pl Normal file
View file

@ -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;
}