protocol.cc 29.1 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 56 57
	/* Send a error string to client */

void send_error(THD *thd, uint sql_errno, const char *err)
{
58
#ifndef EMBEDDED_LIBRARY 
59
  uint length;
60
  char buff[MYSQL_ERRMSG_SIZE+2], *pos;
61
#endif
62 63 64 65 66 67
  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"));

68 69
  if (thd->spcont && thd->spcont->find_handler(sql_errno,
                                               MYSQL_ERROR::WARN_LEVEL_ERROR))
70 71 72
  {
    DBUG_VOID_RETURN;
  }
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
73
#ifndef EMBEDDED_LIBRARY  /* TODO query cache in embedded library*/
74
  query_cache_abort(net);
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
75
#endif
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
  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 */
      }
    }
  }
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
92 93 94 95

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

99 100 101 102 103 104 105 106 107 108 109 110 111
  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);
112 113 114 115
    pos= buff+2;
    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
    {
      /* The first # is to make the protocol backward compatible */
116
      buff[2]= '#';
117
      pos= strmov(buff+3, mysql_errno_to_sqlstate(sql_errno));
118 119
    }
    length= (uint) (strmake(pos, err, MYSQL_ERRMSG_SIZE-1) - buff);
120 121 122 123 124 125 126 127
    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
128
#endif  /* EMBEDDED_LIBRARY*/
129
  thd->is_fatal_error=0;			// Error message is given
130
  thd->net.report_error= 0;
131 132

  /* Abort multi-result sets */
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
133
  thd->lex->found_colon= 0;
134
  thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
135 136 137
  DBUG_VOID_RETURN;
}

138

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
/*
  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");  
156 157
  if (thd->spcont &&
      thd->spcont->find_handler(sql_errno, MYSQL_ERROR::WARN_LEVEL_WARN))
158 159 160
  {
    DBUG_VOID_RETURN;
  }
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
  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;
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
179 180 181
  const char *format;
#ifndef EMBEDDED_LIBRARY
  const char *text_pos;
182
  int head_length= NET_HEADER_SIZE;
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
183
#else
184
  char text_pos[1024];
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
185
#endif
186
  NET *net= &thd->net;
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
187

188 189 190
  DBUG_ENTER("net_printf");
  DBUG_PRINT("enter",("message: %u",errcode));

191 192
  if (thd->spcont && thd->spcont->find_handler(errcode,
                                               MYSQL_ERROR::WARN_LEVEL_ERROR))
193 194 195
  {
    DBUG_VOID_RETURN;
  }
196
  thd->query_error=  1; // needed to catch query errors during replication
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
197
#ifndef EMBEDDED_LIBRARY
198
  query_cache_abort(net);	// Safety
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
199
#endif
200 201 202 203 204 205 206 207 208 209 210 211 212 213
  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;
  }
214 215 216
  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
217
#ifndef EMBEDDED_LIBRARY
218
  text_pos=(char*) net->buff + head_length + offset + 1;
monty@mysql.com's avatar
monty@mysql.com committed
219
  length= (uint) ((char*)net->buff_end - text_pos);
serg@serg.mylan's avatar
serg@serg.mylan committed
220 221
#else
  length=sizeof(text_pos)-1;
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
222
#endif
serg@serg.mylan's avatar
serg@serg.mylan committed
223 224
  length=my_vsnprintf(my_const_cast(char*) (text_pos),
                      min(length, sizeof(net->last_error)),
serg@serg.mylan's avatar
serg@serg.mylan committed
225
                      format,args);
226 227
  va_end(args);

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

296
#ifndef EMBEDDED_LIBRARY
297 298 299 300 301 302
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");
303 304 305 306

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

307 308 309 310 311
  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)
  {
312 313 314 315 316 317
    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));
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
    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));
335 336
  /* We can't anymore send an error to the client */
  thd->net.report_error= 0;
337 338 339
  DBUG_VOID_RETURN;
}

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

/*
  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");
369
  if (net->vio != 0 && !net->no_send_eof)
370
  {
371
    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
372 373 374 375 376
    {
      uchar buff[5];
      uint tmp= min(thd->total_warn_count, 65535);
      buff[0]=254;
      int2store(buff+1, tmp);
377 378 379 380 381 382
      /*
	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)
383
	thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
384
      int2store(buff+3, thd->server_status);
385 386 387 388 389 390 391 392 393 394 395 396
      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;
}
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411

/*
    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;
412
  return my_net_write(net, eof_buff, 1) || net_flush(net);
413 414
}

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

/*
418 419 420 421 422 423 424
  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.
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 481
*/

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;
482
  convert= &thd->convert_buffer;
483 484 485 486 487
#ifndef DEBUG_OFF
  field_types= 0;
#endif
}

488

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

498 499 500 501 502 503 504 505 506 507
/*
  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
508
                4 don't write eof packet
509 510 511 512 513 514 515 516 517

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

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

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

#ifdef TO_BE_DELETED_IN_6
591 592 593 594 595 596 597 598 599 600 601 602
      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
603
#endif
604 605 606 607 608 609 610 611 612 613
      {
	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;
      }
614
    }
615
    local_packet->length((uint) (pos - local_packet->ptr()));
616
    if (flags & SEND_DEFAULTS)
617 618 619 620 621 622 623 624
      item->send(&prot, &tmp);			// Send default value
    if (prot.write())
      break;					/* purecov: inspected */
#ifndef DEBUG_OFF
    field_types[count++]= field.type;
#endif
  }

625 626
  if (flags & SEND_EOF)
    my_net_write(&thd->net, eof_buff, 1);
627 628 629 630 631 632 633
  DBUG_RETURN(prepare_for_send(list));

err:
  send_error(thd,ER_OUT_OF_RESOURCES);		/* purecov: inspected */
  DBUG_RETURN(1);				/* purecov: inspected */
}

634

hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
635 636 637 638 639 640 641 642 643
bool Protocol::send_records_num(List<Item> *list, ulonglong records)
{
  char *pos;
  char buff[20];
  pos=net_store_length(buff, (uint) list->elements);
  pos=net_store_length(pos, records);
  return my_net_write(&thd->net, buff,(uint) (pos-buff));
}

644

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


653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
/*
  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
*/

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


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

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

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


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

729

730 731 732 733 734 735 736 737 738 739 740 741 742
/*
  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)
  {
743 744
    uint dummy_errors;
    return convert->copy(from, length, fromcs, tocs, &dummy_errors) ||
745 746 747 748 749 750
           net_store_data(convert->ptr(), convert->length());
  }
  return net_store_data(from, length);
}


751 752
bool Protocol_simple::store(const char *from, uint length,
			    CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
753 754 755
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
756 757 758
	      field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
	      (field_types[field_pos] >= MYSQL_TYPE_ENUM &&
	       field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
759 760
  field_pos++;
#endif
761
  return store_string_aux(from, length, fromcs, tocs);
762 763 764 765 766 767
}


bool Protocol_simple::store(const char *from, uint length,
			    CHARSET_INFO *fromcs)
{
768
  CHARSET_INFO *tocs= this->thd->variables.character_set_results;
769 770 771 772 773 774 775
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
	      field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
	      (field_types[field_pos] >= MYSQL_TYPE_ENUM &&
	       field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
  field_pos++;
#endif
776
  return store_string_aux(from, length, fromcs, tocs);
777 778 779 780 781 782
}


bool Protocol_simple::store_tiny(longlong from)
{
#ifndef DEBUG_OFF
783 784
  DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TINY);
  field_pos++;
785 786
#endif
  char buff[20];
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
787
  return net_store_data((char*) buff,
788 789 790
			(uint) (int10_to_str((int) from,buff, -10)-buff));
}

791

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

804

805 806 807
bool Protocol_simple::store_long(longlong from)
{
#ifndef DEBUG_OFF
808 809 810 811
  DBUG_ASSERT(field_types == 0 ||
              field_types[field_pos] == MYSQL_TYPE_INT24 ||
              field_types[field_pos] == MYSQL_TYPE_LONG);
  field_pos++;
812 813
#endif
  char buff[20];
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
814
  return net_store_data((char*) buff,
815 816 817 818 819 820 821 822
			(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 ||
823 824
	      field_types[field_pos] == MYSQL_TYPE_LONGLONG);
  field_pos++;
825 826
#endif
  char buff[22];
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
827
  return net_store_data((char*) buff,
828 829 830 831 832 833 834 835 836 837
			(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 ||
838 839
	      field_types[field_pos] == MYSQL_TYPE_FLOAT);
  field_pos++;
840
#endif
841
  buffer->set((double) from, decimals, thd->charset());
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
842
  return net_store_data((char*) buffer->ptr(), buffer->length());
843 844
}

845

846 847 848 849
bool Protocol_simple::store(double from, uint32 decimals, String *buffer)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
850 851
	      field_types[field_pos] == MYSQL_TYPE_DOUBLE);
  field_pos++;
852
#endif
853
  buffer->set(from, decimals, thd->charset());
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
854
  return net_store_data((char*) buffer->ptr(), buffer->length());
855 856 857 858 859
}


bool Protocol_simple::store(Field *field)
{
860 861
  if (field->is_null())
    return store_null();
862 863 864 865
#ifndef DEBUG_OFF
  field_pos++;
#endif
  char buff[MAX_FIELD_WIDTH];
866
  String str(buff,sizeof(buff), &my_charset_bin);
867 868
  CHARSET_INFO *tocs= this->thd->variables.character_set_results;

869
  field->val_str(&str);
870
  return store_string_aux(str.ptr(), str.length(), str.charset(), tocs);
871 872 873
}


874 875 876 877 878 879 880
/*
   TODO:
        Second_part format ("%06") needs to change when 
        we support 0-6 decimals for time.
*/


881 882 883 884
bool Protocol_simple::store(TIME *tm)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
885 886 887
	      field_types[field_pos] == MYSQL_TYPE_DATETIME ||
	      field_types[field_pos] == MYSQL_TYPE_TIMESTAMP);
  field_pos++;
888 889
#endif
  char buff[40];
890 891 892 893 894 895 896 897 898 899 900
  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);
901 902 903 904 905 906 907
}


bool Protocol_simple::store_date(TIME *tm)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
908 909
	      field_types[field_pos] == MYSQL_TYPE_DATE);
  field_pos++;
910
#endif
911 912 913
  char buff[MAX_DATE_STRING_REP_LENGTH];
  int length= my_date_to_str(tm, buff);
  return net_store_data(buff, (uint) length);
914 915 916
}


917 918 919 920 921 922
/*
   TODO:
        Second_part format ("%06") needs to change when 
        we support 0-6 decimals for time.
*/

923 924 925 926
bool Protocol_simple::store_time(TIME *tm)
{
#ifndef DEBUG_OFF
  DBUG_ASSERT(field_types == 0 ||
927 928
	      field_types[field_pos] == MYSQL_TYPE_TIME);
  field_pos++;
929 930
#endif
  char buff[40];
931
  uint length;
932
  uint day= (tm->year || tm->month) ? 0 : tm->day;
933 934 935 936 937 938 939 940
  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);
941 942 943 944 945
}


/****************************************************************************
  Functions to handle the binary protocol used with prepared statements
946 947 948

  Data format:

949 950 951 952 953 954 955 956 957 958 959 960
   [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
961 962 963 964
****************************************************************************/

bool Protocol_prep::prepare_for_send(List<Item> *item_list)
{
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
965
  Protocol::prepare_for_send(item_list);
966 967
  bit_fields= (field_count+9)/8;
  if (packet->alloc(bit_fields+1))
968 969 970 971 972 973 974 975
    return 1;
  /* prepare_for_resend will be called after this one */
  return 0;
}


void Protocol_prep::prepare_for_resend()
{
976 977
  packet->length(bit_fields+1);
  bzero((char*) packet->ptr(), 1+bit_fields);
978 979 980 981
  field_pos=0;
}


982
bool Protocol_prep::store(const char *from, uint length, CHARSET_INFO *fromcs)
983
{
984
  CHARSET_INFO *tocs= thd->variables.character_set_results;
985
  field_pos++;
986
  return store_string_aux(from, length, fromcs, tocs);
987 988
}

989 990 991 992
bool Protocol_prep::store(const char *from,uint length,
			  CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
  field_pos++;
993
  return store_string_aux(from, length, fromcs, tocs);
994 995
}

996 997
bool Protocol_prep::store_null()
{
998
  uint offset= (field_pos+2)/8+1, bit= (1 << ((field_pos+2) & 7));
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
  /* 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;
1012
  return packet->append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
1013 1014 1015 1016 1017 1018
}


bool Protocol_prep::store_short(longlong from)
{
  field_pos++;
1019
  char *to= packet->prep_append(2, PACKET_BUFFER_EXTRA_ALLOC);
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
  if (!to)
    return 1;
  int2store(to, (int) from);
  return 0;
}


bool Protocol_prep::store_long(longlong from)
{
  field_pos++;
1030
  char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
  if (!to)
    return 1;
  int4store(to, from);
  return 0;
}


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


bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
{
  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;
  float4store(to, from);
  return 0;
}


bool Protocol_prep::store(double from, uint32 decimals, String *buffer)
{
  field_pos++;
1063
  char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
  if (!to)
    return 1;
  float8store(to, from);
  return 0;
}


bool Protocol_prep::store(Field *field)
{
  /*
1074
    We should not increment field_pos here as send_binary() will call another
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
    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;
1089

1090
  int2store(pos, tm->year);
1091 1092 1093 1094 1095
  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;
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
  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
1106
  return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
}

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)
{
1119
  char buff[13], *pos;
1120 1121 1122 1123
  uint length;
  field_pos++;
  pos= buff+1;
  pos[0]= tm->neg ? 1 : 0;
1124 1125 1126 1127 1128 1129 1130
  if (tm->hour >= 24)
  {
    /* Fix if we come from Item::send */
    uint days= tm->hour/24;
    tm->hour-= days*24;
    tm->day+= days;
  }
1131
  int4store(pos+1, tm->day);
1132 1133 1134 1135
  pos[5]= (uchar) tm->hour;
  pos[6]= (uchar) tm->minute;
  pos[7]= (uchar) tm->second;
  int4store(pos+8, tm->second_part);
1136
  if (tm->second_part)
1137
    length=12;
1138
  else if (tm->hour || tm->minute || tm->second || tm->day)
1139
    length=8;
1140 1141 1142
  else
    length=0;
  buff[0]=(char) length;			// Length is stored first
1143
  return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
1144
}