diff options
Diffstat (limited to 'sql/net_pkg.cc')
-rw-r--r-- | sql/net_pkg.cc | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc new file mode 100644 index 00000000000..27065ee776e --- /dev/null +++ b/sql/net_pkg.cc @@ -0,0 +1,329 @@ +/* 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(NET *net, uint sql_errno, const char *err) +{ + uint length; + char buff[MYSQL_ERRMSG_SIZE+2]; + THD *thd=current_thd; + DBUG_ENTER("send_error"); + DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, + err ? err : net->last_error[0] ? + net->last_error : "NULL")); + + if (thd) + thd->query_error = 1; // needed to catch query errors during replication + if (!err) + { + if (sql_errno) + err=ER(sql_errno); + else if (!err) + { + 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 && thd->bootstrap) + { + 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=strlen(err); + set_if_smaller(length,MYSQL_ERRMSG_SIZE); + } + VOID(net_write_command(net,(uchar) 255,(char*) err,length)); + if (thd) + thd->fatal_error=0; // Error message is given + DBUG_VOID_RETURN; +} + +/** +** write error package and flush to client +** It's a little too low level, but I don't want to allow another buffer +*/ +/* VARARGS3 */ + +void +net_printf(NET *net, uint errcode, ...) +{ + va_list args; + uint length,offset; + const char *format,*text_pos; + int head_length= NET_HEADER_SIZE; + THD *thd=current_thd; + DBUG_ENTER("net_printf"); + DBUG_PRINT("enter",("message: %u",errcode)); + + if(thd) thd->query_error = 1; + // if we are here, something is wrong :-) + + va_start(args,errcode); + format=ER(errcode); + 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=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 && thd->bootstrap) + { + 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)); + if (thd) + thd->fatal_error=0; // Error message is given + DBUG_VOID_RETURN; +} + + +void +send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message) +{ + if(net->no_send_ok) + 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 (net->return_status) + { + int2store(pos,*net->return_status); + pos+=2; + } + if (message) + pos=net_store_data((char*) pos,message); + if (net->vio != 0) + { + VOID(my_net_write(net,buff,(uint) (pos-buff))); + VOID(net_flush(net)); + } + DBUG_VOID_RETURN; +} + +void +send_eof(NET *net,bool no_flush) +{ + static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ + DBUG_ENTER("send_eof"); + if (net->vio != 0) + { + 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=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=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)); + 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()); +} |