protocol.cc 30.7 KB
Newer Older
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1
/* Copyright (C) 2000-2003 MySQL AB
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

   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"
27
#include "sp_rcontext.h"
28 29
#include <stdarg.h>

30 31
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;

hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
32 33
#ifndef EMBEDDED_LIBRARY
bool Protocol::net_store_data(const char *from, uint length)
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
34 35 36
#else
bool Protocol_prep::net_store_data(const char *from, uint length)
#endif
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
37 38
{
  ulong packet_length=packet->length();
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
39 40 41 42 43 44
  /* 
     The +9 comes from that strings of length longer than 16M require
     9 bytes to be stored (see net_store_length).
  */
  if (packet_length+9+length > packet->alloced_length() &&
      packet->realloc(packet_length+9+length))
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
45 46 47 48 49 50 51 52 53
    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;
}


54 55
	/* Send a error string to client */

56
void net_send_error(THD *thd, uint sql_errno, const char *err)
57
{
58
#ifndef EMBEDDED_LIBRARY 
59
  uint length;
60
  char buff[MYSQL_ERRMSG_SIZE+2], *pos;
61
#endif
62
  NET *net= &thd->net;
serg@serg.mylan's avatar
serg@serg.mylan committed
63
  bool generate_warning= thd->killed != THD::KILL_CONNECTION;
64
  DBUG_ENTER("net_send_error");
65 66 67 68
  DBUG_PRINT("enter",("sql_errno: %d  err: %s", sql_errno,
		      err ? err : net->last_error[0] ?
		      net->last_error : "NULL"));

69 70 71 72 73 74
  if (net && net->no_send_error)
  {
    thd->clear_error();
    DBUG_PRINT("info", ("sending error messages prohibited"));
    DBUG_VOID_RETURN;
  }
75 76
  if (thd->spcont && thd->spcont->find_handler(sql_errno,
                                               MYSQL_ERROR::WARN_LEVEL_ERROR))
77 78 79
  {
    DBUG_VOID_RETURN;
  }
80 81 82 83 84 85 86 87
  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])
88
      {
89
	sql_errno=net->last_errno;
90 91
        generate_warning= 0;            // This warning has already been given
      }
92 93 94 95 96 97
      else
      {
	sql_errno=ER_UNKNOWN_ERROR;
	err=ER(sql_errno);	 /* purecov: inspected */
      }
    }
98 99 100 101 102 103
  }

  if (generate_warning)
  {
    /* Error that we have not got with my_error() */
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, sql_errno, err);
104
  }
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
105 106 107 108

#ifdef EMBEDDED_LIBRARY
  net->last_errno= sql_errno;
  strmake(net->last_error, err, sizeof(net->last_error)-1);
109
  strmov(net->sqlstate, mysql_errno_to_sqlstate(sql_errno));
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
110 111
#else

112 113 114 115 116 117 118 119 120 121 122 123 124
  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);
125 126 127 128
    pos= buff+2;
    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
    {
      /* The first # is to make the protocol backward compatible */
129
      buff[2]= '#';
130
      pos= strmov(buff+3, mysql_errno_to_sqlstate(sql_errno));
131 132
    }
    length= (uint) (strmake(pos, err, MYSQL_ERRMSG_SIZE-1) - buff);
133 134 135 136 137 138 139 140
    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));
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
141
#endif  /* EMBEDDED_LIBRARY*/
142
  thd->is_fatal_error=0;			// Error message is given
143
  thd->net.report_error= 0;
144 145

  /* Abort multi-result sets */
146
  thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
147 148 149 150 151 152 153 154 155 156
  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
157
net_printf_error(THD *thd, uint errcode, ...)
158 159 160
{
  va_list args;
  uint length,offset;
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
161 162 163
  const char *format;
#ifndef EMBEDDED_LIBRARY
  const char *text_pos;
164
  int head_length= NET_HEADER_SIZE;
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
165
#else
166
  char text_pos[1024];
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
167
#endif
168
  NET *net= &thd->net;
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
169

170
  DBUG_ENTER("net_printf_error");
171 172
  DBUG_PRINT("enter",("message: %u",errcode));

173 174 175 176 177 178 179
  if (net && net->no_send_error)
  {
    thd->clear_error();
    DBUG_PRINT("info", ("sending error messages prohibited"));
    DBUG_VOID_RETURN;
  }

180 181
  if (thd->spcont && thd->spcont->find_handler(errcode,
                                               MYSQL_ERROR::WARN_LEVEL_ERROR))
182 183 184
  {
    DBUG_VOID_RETURN;
  }
185
  thd->query_error=  1; // needed to catch query errors during replication
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
186
#ifndef EMBEDDED_LIBRARY
187
  query_cache_abort(net);	// Safety
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
188
#endif
189 190
  va_start(args,errcode);
  /*
191 192
    The following is needed to make net_printf_error() work with 0 argument
    for errorcode and use the argument after that as the format string. This
193 194 195 196 197 198 199 200 201 202
    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;
  }
203 204 205
  offset= (net->return_errno ?
	   ((thd->client_capabilities & CLIENT_PROTOCOL_41) ?
	    2+SQLSTATE_LENGTH+1 : 2) : 0);
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
206
#ifndef EMBEDDED_LIBRARY
207
  text_pos=(char*) net->buff + head_length + offset + 1;
monty@mysql.com's avatar
monty@mysql.com committed
208
  length= (uint) ((char*)net->buff_end - text_pos);
serg@serg.mylan's avatar
serg@serg.mylan committed
209 210
#else
  length=sizeof(text_pos)-1;
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
211
#endif
serg@serg.mylan's avatar
serg@serg.mylan committed
212 213
  length=my_vsnprintf(my_const_cast(char*) (text_pos),
                      min(length, sizeof(net->last_error)),
serg@serg.mylan's avatar
serg@serg.mylan committed
214
                      format,args);
215 216
  va_end(args);

217 218 219 220
  /* Replication slave relies on net->last_* to see if there was error */
  net->last_errno= errcode;
  strmake(net->last_error, text_pos, sizeof(net->last_error)-1);

hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
221
#ifndef EMBEDDED_LIBRARY
222 223 224 225
  if (net->vio == 0)
  {
    if (thd->bootstrap)
    {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
226 227 228 229
      /*
	In bootstrap it's ok to print on stderr
	This may also happen when we get an error from a slave thread
      */
230
      fprintf(stderr,"ERROR: %d  %s\n",errcode,text_pos);
231
      thd->fatal_error();
232 233 234 235 236 237 238 239
    }
    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)
240 241 242 243 244
  {
    uchar *pos= net->buff+head_length+1;
    int2store(pos, errcode);
    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
    {
245 246
      pos[2]= '#';      /* To make the protocol backward compatible */
      memcpy(pos+3, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH);
247 248
    }
  }
249
  VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset));
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
250 251 252
#else
  net->last_errno= errcode;
  strmake(net->last_error, text_pos, length);
253
  strmake(net->sqlstate, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH);
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
254
#endif
serg@serg.mylan's avatar
serg@serg.mylan committed
255
  if (thd->killed != THD::KILL_CONNECTION)
serg@serg.mylan's avatar
serg@serg.mylan committed
256 257
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, errcode,
                 text_pos ? text_pos : ER(errcode));
258
  thd->is_fatal_error=0;			// Error message is given
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
  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
*/    

288
#ifndef EMBEDDED_LIBRARY
289 290 291 292 293 294
void
send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
{
  NET *net= &thd->net;
  char buff[MYSQL_ERRMSG_SIZE+10],*pos;
  DBUG_ENTER("send_ok");
295 296 297 298

  if (net->no_send_ok || !net->vio)	// hack for re-parsing queries
    DBUG_VOID_RETURN;

299 300 301 302 303
  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)
  {
304 305 306 307 308 309
    DBUG_PRINT("info",
	       ("affected_rows: %lu  id: %lu  status: %u  warning_count: %u",
		(ulong) affected_rows,		
		(ulong) id,
		(uint) (thd->server_status & 0xffff),
		(uint) thd->total_warn_count));
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    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));
327 328
  /* We can't anymore send an error to the client */
  thd->net.report_error= 0;
329
  thd->net.no_send_error= 1;
330
  DBUG_PRINT("info", ("OK sent, so no more error sending allowed"));
331

332 333 334
  DBUG_VOID_RETURN;
}

335
static char eof_buff[1]= { (char) 254 };        /* Marker for end of fields */
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363

/*
  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)
{
  NET *net= &thd->net;
  DBUG_ENTER("send_eof");
364
  if (net->vio != 0 && !net->no_send_eof)
365
  {
366
    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
367 368
    {
      uchar buff[5];
369 370 371
      /* Don't send warn count during SP execution, as the warn_list
         is cleared between substatements, and mysqltest gets confused */
      uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535));
372 373
      buff[0]=254;
      int2store(buff+1, tmp);
374 375 376 377 378 379
      /*
	The following test should never be true, but it's better to do it
	because if 'is_fatal_error' is set the server is not going to execute
	other queries (see the if test in dispatch_command / COM_QUERY)
      */
      if (thd->is_fatal_error)
380
	thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
381
      int2store(buff+3, thd->server_status);
382 383 384 385 386 387 388 389 390
      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));
    }
391
    thd->net.no_send_error= 1;
392
    DBUG_PRINT("info", ("EOF sent, so no more error sending allowed"));
393 394 395
  }
  DBUG_VOID_RETURN;
}
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410

/*
    Please client to send scrambled_password in old format.
  SYNOPSYS
    send_old_password_request()
    thd thread handle
     
  RETURN VALUE
    0  ok
   !0  error
*/

bool send_old_password_request(THD *thd)
{
  NET *net= &thd->net;
411
  return my_net_write(net, eof_buff, 1) || net_flush(net);
412 413
}

hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
414
#endif /* EMBEDDED_LIBRARY */
415 416

/*
417 418 419 420 421 422 423
  Faster net_store_length when we know that length is less than 65536.
  We keep a separate version for that range because it's widely used in
  libmysql.
  uint is used as agrument type because of MySQL type conventions:
  uint for 0..65536
  ulong for 0..4294967296
  ulonglong for bigger numbers.
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
*/

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


/****************************************************************************
  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;
}


/*****************************************************************************
  Default Protocol functions
*****************************************************************************/

void Protocol::init(THD *thd_arg)
{
  thd=thd_arg;
  packet= &thd->packet;
481
  convert= &thd->convert_buffer;
482 483 484 485 486
#ifndef DEBUG_OFF
  field_types= 0;
#endif
}

487

488 489 490 491 492 493 494 495 496
bool Protocol::flush()
{
#ifndef EMBEDDED_LIBRARY
  return net_flush(&thd->net);
#else
  return 0;
#endif
}

497 498 499 500 501 502 503 504 505 506
/*
  Send name and type of result to client.

  SYNOPSIS
    send_fields()
    THD		Thread data object
    list	List of items to send to client
    flag	Bit mask with the following functions:
		1 send number of rows
		2 send default values
507
                4 don't write eof packet
508 509 510 511 512 513 514 515 516

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

hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
517
#ifndef EMBEDDED_LIBRARY
monty@mysql.com's avatar
monty@mysql.com committed
518
bool Protocol::send_fields(List<Item> *list, uint flags)
519 520 521 522
{
  List_iterator_fast<Item> it(*list);
  Item *item;
  char buff[80];
523
  String tmp((char*) buff,sizeof(buff),&my_charset_bin);
524
  Protocol_simple prot(thd);
525
  String *local_packet= prot.storage_packet();
526
  CHARSET_INFO *thd_charset= thd->variables.character_set_results;
527 528
  DBUG_ENTER("send_fields");

529
  if (flags & SEND_NUM_ROWS)
530 531 532 533 534 535 536 537 538 539 540 541 542 543
  {				// 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;
544
    CHARSET_INFO *cs= system_charset_info;
545 546
    Send_field field;
    item->make_field(&field);
547 548 549 550 551

    /* Keep things compatible for old clients */
    if (field.type == MYSQL_TYPE_VARCHAR)
      field.type= MYSQL_TYPE_VAR_STRING;

552 553 554 555
    prot.prepare_for_resend();

    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
    {
556
      if (prot.store("def", 3, cs, thd_charset) ||
557 558
	  prot.store(field.db_name, (uint) strlen(field.db_name),
		     cs, thd_charset) ||
559
	  prot.store(field.table_name, (uint) strlen(field.table_name),
560
		     cs, thd_charset) ||
561
	  prot.store(field.org_table_name, (uint) strlen(field.org_table_name),
562
		     cs, thd_charset) ||
563
	  prot.store(field.col_name, (uint) strlen(field.col_name),
564
		     cs, thd_charset) ||
565
	  prot.store(field.org_col_name, (uint) strlen(field.org_col_name),
566
		     cs, thd_charset) ||
567
	  local_packet->realloc(local_packet->length()+12))
568
	goto err;
569
      /* Store fixed length fields */
570
      pos= (char*) local_packet->ptr()+local_packet->length();
571
      *pos++= 12;				// Length of packed fields
572
      if (item->collation.collation == &my_charset_bin || thd_charset == NULL)
573 574
      {
        /* No conversion */
575
        int2store(pos, field.charsetnr);
576 577
        int4store(pos+2, field.length);
      }
578
      else
579 580 581 582 583 584
      {
        /* With conversion */
        int2store(pos, thd_charset->number);
        uint char_len= field.length / item->collation.collation->mbmaxlen;
        int4store(pos+2, char_len * thd_charset->mbmaxlen);
      }
585 586 587
      pos[6]= field.type;
      int2store(pos+7,field.flags);
      pos[9]= (char) field.decimals;
588
      pos[10]= 0;				// For the future
589 590
      pos[11]= 0;				// For the future
      pos+= 12;
591 592 593
    }
    else
    {
594
      if (prot.store(field.table_name, (uint) strlen(field.table_name),
595
		     cs, thd_charset) ||
596
	  prot.store(field.col_name, (uint) strlen(field.col_name),
597
		     cs, thd_charset) ||
598
	  local_packet->realloc(local_packet->length()+10))
599
	goto err;
600
      pos= (char*) local_packet->ptr()+local_packet->length();
601 602

#ifdef TO_BE_DELETED_IN_6
603 604 605 606 607 608 609 610 611 612 613 614
      if (!(thd->client_capabilities & CLIENT_LONG_FLAG))
      {
	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;
	pos+= 9;
      }
      else
615
#endif
616 617 618 619 620 621 622 623 624 625
      {
	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;
	pos+= 10;
      }
626
    }
627
    local_packet->length((uint) (pos - local_packet->ptr()));
628
    if (flags & SEND_DEFAULTS)
629 630 631 632 633 634 635 636
      item->send(&prot, &tmp);			// Send default value
    if (prot.write())
      break;					/* purecov: inspected */
#ifndef DEBUG_OFF
    field_types[count++]= field.type;
#endif
  }

637 638
  if (flags & SEND_EOF)
    my_net_write(&thd->net, eof_buff, 1);
639 640 641
  DBUG_RETURN(prepare_for_send(list));

err:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
642 643
  my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
             MYF(0));	/* purecov: inspected */
644 645 646
  DBUG_RETURN(1);				/* purecov: inspected */
}

647

648 649 650
bool Protocol::write()
{
  DBUG_ENTER("Protocol::write");
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
651
  DBUG_RETURN(my_net_write(&thd->net, packet->ptr(), packet->length()));
652
}
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
653 654 655
#endif /* EMBEDDED_LIBRARY */


656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
/*
  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
*/

671
bool Protocol::store(const char *from, CHARSET_INFO *cs)
672 673 674 675
{
  if (!from)
    return store_null();
  uint length= strlen(from);
676
  return store(from, length, cs);
677 678 679 680 681 682 683 684 685 686
}


/*
  Send a set of strings as one long string with ',' in between
*/

bool Protocol::store(I_List<i_string>* str_list)
{
  char buf[256];
687
  String tmp(buf, sizeof(buf), &my_charset_bin);
688
  uint32 len;
689 690 691
  I_List_iterator<i_string> it(*str_list);
  i_string* s;

692
  tmp.length(0);
693 694 695
  while ((s=it++))
  {
    tmp.append(s->ptr);
696
    tmp.append(',');
697
  }
698 699
  if ((len= tmp.length()))
    len--;					// Remove last ','
700
  return store((char*) tmp.ptr(), len,  tmp.charset());
701 702 703 704 705 706 707 708 709 710 711
}


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

hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
712
#ifndef EMBEDDED_LIBRARY
713 714 715 716 717 718 719 720 721 722 723 724 725 726
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];
727
  buff[0]= (char)251;
728
  return packet->append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
729
}
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
730
#endif
731

732

733 734 735 736 737 738 739 740 741 742 743 744 745
/*
  Auxilary function to convert string to the given character set
  and store in network buffer.
*/

bool Protocol::store_string_aux(const char *from, uint length,
                                CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
  /* 'tocs' is set 0 when client issues SET character_set_results=NULL */
  if (tocs && !my_charset_same(fromcs, tocs) &&
      fromcs != &my_charset_bin &&
      tocs != &my_charset_bin)
  {
746 747
    uint dummy_errors;
    return convert->copy(from, length, fromcs, tocs, &dummy_errors) ||
748 749 750 751 752 753
           net_store_data(convert->ptr(), convert->length());
  }
  return net_store_data(from, length);
}


754 755
bool Protocol_simple::store(const char *from, uint length,
			    CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
756 757 758
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
759
	      field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
760
              field_types[field_pos] == MYSQL_TYPE_BIT ||
761
              field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL ||
762 763
	      (field_types[field_pos] >= MYSQL_TYPE_ENUM &&
	       field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
764 765
  field_pos++;
#endif
766
  return store_string_aux(from, length, fromcs, tocs);
767 768 769 770 771 772
}


bool Protocol_simple::store(const char *from, uint length,
			    CHARSET_INFO *fromcs)
{
773
  CHARSET_INFO *tocs= this->thd->variables.character_set_results;
774 775 776
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
	      field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
777
              field_types[field_pos] == MYSQL_TYPE_BIT ||
778
              field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL ||
779 780 781 782
	      (field_types[field_pos] >= MYSQL_TYPE_ENUM &&
	       field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
  field_pos++;
#endif
783
  return store_string_aux(from, length, fromcs, tocs);
784 785 786 787 788 789
}


bool Protocol_simple::store_tiny(longlong from)
{
#ifndef DEBUG_OFF
790 791
  DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TINY);
  field_pos++;
792 793
#endif
  char buff[20];
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
794
  return net_store_data((char*) buff,
795 796 797
			(uint) (int10_to_str((int) from,buff, -10)-buff));
}

798

799 800 801 802
bool Protocol_simple::store_short(longlong from)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
803
	      field_types[field_pos] == MYSQL_TYPE_YEAR ||
804 805
	      field_types[field_pos] == MYSQL_TYPE_SHORT);
  field_pos++;
806 807
#endif
  char buff[20];
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
808
  return net_store_data((char*) buff,
809 810 811
			(uint) (int10_to_str((int) from,buff, -10)-buff));
}

812

813 814 815
bool Protocol_simple::store_long(longlong from)
{
#ifndef DEBUG_OFF
816 817 818 819
  DBUG_ASSERT(field_types == 0 ||
              field_types[field_pos] == MYSQL_TYPE_INT24 ||
              field_types[field_pos] == MYSQL_TYPE_LONG);
  field_pos++;
820 821
#endif
  char buff[20];
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
822
  return net_store_data((char*) buff,
823
			(uint) (int10_to_str((int)from,buff, (from <0)?-10:10)-buff));
824 825 826 827 828 829 830
}


bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
831 832
	      field_types[field_pos] == MYSQL_TYPE_LONGLONG);
  field_pos++;
833 834
#endif
  char buff[22];
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
835
  return net_store_data((char*) buff,
836 837 838 839 840 841
			(uint) (longlong10_to_str(from,buff,
						  unsigned_flag ? 10 : -10)-
				buff));
}


842 843 844 845 846 847 848
bool Protocol_simple::store_decimal(const my_decimal *d)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
              field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
  field_pos++;
#endif
849 850 851
  char buff[DECIMAL_MAX_STR_LENGTH];
  String str(buff, sizeof(buff), &my_charset_bin);
  (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
852 853 854 855
  return net_store_data(str.ptr(), str.length());
}


856 857 858 859
bool Protocol_simple::store(float from, uint32 decimals, String *buffer)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
860 861
	      field_types[field_pos] == MYSQL_TYPE_FLOAT);
  field_pos++;
862
#endif
863
  buffer->set((double) from, decimals, thd->charset());
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
864
  return net_store_data((char*) buffer->ptr(), buffer->length());
865 866
}

867

868 869 870 871
bool Protocol_simple::store(double from, uint32 decimals, String *buffer)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
872 873
	      field_types[field_pos] == MYSQL_TYPE_DOUBLE);
  field_pos++;
874
#endif
875
  buffer->set(from, decimals, thd->charset());
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
876
  return net_store_data((char*) buffer->ptr(), buffer->length());
877 878 879 880 881
}


bool Protocol_simple::store(Field *field)
{
882 883
  if (field->is_null())
    return store_null();
884 885 886 887
#ifndef DEBUG_OFF
  field_pos++;
#endif
  char buff[MAX_FIELD_WIDTH];
888
  String str(buff,sizeof(buff), &my_charset_bin);
889 890
  CHARSET_INFO *tocs= this->thd->variables.character_set_results;

891
  field->val_str(&str);
892
  return store_string_aux(str.ptr(), str.length(), str.charset(), tocs);
893 894 895
}


896 897 898 899 900 901 902
/*
   TODO:
        Second_part format ("%06") needs to change when 
        we support 0-6 decimals for time.
*/


903 904 905 906
bool Protocol_simple::store(TIME *tm)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
907 908 909
	      field_types[field_pos] == MYSQL_TYPE_DATETIME ||
	      field_types[field_pos] == MYSQL_TYPE_TIMESTAMP);
  field_pos++;
910 911
#endif
  char buff[40];
912 913 914 915 916 917 918 919 920 921 922
  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));
  if (tm->second_part)
    length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part));
  return net_store_data((char*) buff, length);
923 924 925 926 927 928 929
}


bool Protocol_simple::store_date(TIME *tm)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
930 931
	      field_types[field_pos] == MYSQL_TYPE_DATE);
  field_pos++;
932
#endif
933 934 935
  char buff[MAX_DATE_STRING_REP_LENGTH];
  int length= my_date_to_str(tm, buff);
  return net_store_data(buff, (uint) length);
936 937 938
}


939 940 941 942 943 944
/*
   TODO:
        Second_part format ("%06") needs to change when 
        we support 0-6 decimals for time.
*/

945 946 947 948
bool Protocol_simple::store_time(TIME *tm)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
949 950
	      field_types[field_pos] == MYSQL_TYPE_TIME);
  field_pos++;
951 952
#endif
  char buff[40];
953
  uint length;
954
  uint day= (tm->year || tm->month) ? 0 : tm->day;
955 956 957 958 959 960 961 962
  length= my_sprintf(buff,(buff, "%s%02ld:%02d:%02d",
			   tm->neg ? "-" : "",
			   (long) day*24L+(long) tm->hour,
			   (int) tm->minute,
			   (int) tm->second));
  if (tm->second_part)
    length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part));
  return net_store_data((char*) buff, length);
963 964 965 966 967
}


/****************************************************************************
  Functions to handle the binary protocol used with prepared statements
968 969 970

  Data format:

971 972 973 974 975 976 977 978 979 980 981 982
   [ok:1]                            reserved ok packet
   [null_field:(field_count+7+2)/8]  reserved to send null data. The size is
                                     calculated using:
                                     bit_fields= (field_count+7+2)/8; 
                                     2 bits are reserved for identifying type
				     of package.
   [[length]data]                    data field (the length applies only for 
                                     string/binary/time/timestamp fields and 
                                     rest of them are not sent as they have 
                                     the default length that client understands
                                     based on the field type
   [..]..[[length]data]              data
983 984 985 986
****************************************************************************/

bool Protocol_prep::prepare_for_send(List<Item> *item_list)
{
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
987
  Protocol::prepare_for_send(item_list);
988 989
  bit_fields= (field_count+9)/8;
  if (packet->alloc(bit_fields+1))
990 991 992 993 994 995 996 997
    return 1;
  /* prepare_for_resend will be called after this one */
  return 0;
}


void Protocol_prep::prepare_for_resend()
{
998 999
  packet->length(bit_fields+1);
  bzero((char*) packet->ptr(), 1+bit_fields);
1000 1001 1002 1003
  field_pos=0;
}


1004
bool Protocol_prep::store(const char *from, uint length, CHARSET_INFO *fromcs)
1005
{
1006
  CHARSET_INFO *tocs= thd->variables.character_set_results;
1007
  field_pos++;
1008
  return store_string_aux(from, length, fromcs, tocs);
1009 1010
}

1011 1012 1013 1014
bool Protocol_prep::store(const char *from,uint length,
			  CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
  field_pos++;
1015
  return store_string_aux(from, length, fromcs, tocs);
1016 1017
}

1018 1019
bool Protocol_prep::store_null()
{
1020
  uint offset= (field_pos+2)/8+1, bit= (1 << ((field_pos+2) & 7));
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
  /* 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)
{
  char buff[1];
  field_pos++;
  buff[0]= (uchar) from;
1034
  return packet->append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
1035 1036 1037 1038 1039 1040
}


bool Protocol_prep::store_short(longlong from)
{
  field_pos++;
1041
  char *to= packet->prep_append(2, PACKET_BUFFER_EXTRA_ALLOC);
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
  if (!to)
    return 1;
  int2store(to, (int) from);
  return 0;
}


bool Protocol_prep::store_long(longlong from)
{
  field_pos++;
1052
  char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
  if (!to)
    return 1;
  int4store(to, from);
  return 0;
}


bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag)
{
  field_pos++;
1063
  char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
1064 1065 1066 1067 1068 1069
  if (!to)
    return 1;
  int8store(to, from);
  return 0;
}

1070 1071 1072 1073 1074 1075 1076
bool Protocol_prep::store_decimal(const my_decimal *d)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
              field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
  field_pos++;
#endif
1077 1078 1079
  char buff[DECIMAL_MAX_STR_LENGTH];
  String str(buff, sizeof(buff), &my_charset_bin);
  (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
1080 1081
  return store(str.ptr(), str.length(), str.charset());
}
1082 1083 1084 1085

bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
{
  field_pos++;
1086
  char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096
  if (!to)
    return 1;
  float4store(to, from);
  return 0;
}


bool Protocol_prep::store(double from, uint32 decimals, String *buffer)
{
  field_pos++;
1097
  char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
  if (!to)
    return 1;
  float8store(to, from);
  return 0;
}


bool Protocol_prep::store(Field *field)
{
  /*
1108
    We should not increment field_pos here as send_binary() will call another
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
    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)
{
  char buff[12],*pos;
  uint length;
  field_pos++;
  pos= buff+1;
1123

1124
  int2store(pos, tm->year);
1125 1126 1127 1128 1129
  pos[2]= (uchar) tm->month;
  pos[3]= (uchar) tm->day;
  pos[4]= (uchar) tm->hour;
  pos[5]= (uchar) tm->minute;
  pos[6]= (uchar) tm->second;
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
  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
1140
  return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
}

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)
{
1153
  char buff[13], *pos;
1154 1155 1156 1157
  uint length;
  field_pos++;
  pos= buff+1;
  pos[0]= tm->neg ? 1 : 0;
1158 1159 1160 1161 1162 1163 1164
  if (tm->hour >= 24)
  {
    /* Fix if we come from Item::send */
    uint days= tm->hour/24;
    tm->hour-= days*24;
    tm->day+= days;
  }
1165
  int4store(pos+1, tm->day);
1166 1167 1168 1169
  pos[5]= (uchar) tm->hour;
  pos[6]= (uchar) tm->minute;
  pos[7]= (uchar) tm->second;
  int4store(pos+8, tm->second_part);
1170
  if (tm->second_part)
1171
    length=12;
1172
  else if (tm->hour || tm->minute || tm->second || tm->day)
1173
    length=8;
1174 1175 1176
  else
    length=0;
  buff[0]=(char) length;			// Length is stored first
1177
  return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
1178
}