protocol.cc 37.7 KB
Newer Older
1
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
2 3 4

   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
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
6 7 8 9 10 11 12 13 14 15

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

unknown's avatar
unknown committed
16 17 18 19
/**
  @file

  Low level functions for storing data to be send to the MySQL client.
20 21 22
  The actual communction is handled by the net_xxx functions in net_serv.cc
*/

23
#ifdef USE_PRAGMA_IMPLEMENTATION
24 25 26 27 28 29
#pragma implementation				// gcc: Class implementation
#endif

#include "mysql_priv.h"
#include <stdarg.h>

30
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
31
/* Declared non-static only because of the embedded library. */
32 33 34
bool net_send_error_packet(THD *thd, uint sql_errno, const char *err);
bool net_send_ok(THD *, uint, uint, ha_rows, ulonglong, const char *);
bool net_send_eof(THD *thd, uint server_status, uint total_warn_count);
35
#ifndef EMBEDDED_LIBRARY
36
static bool write_eof_packet(THD *thd, NET *net,
37
                             uint server_status, uint total_warn_count);
38
#endif
39

unknown's avatar
SCRUM  
unknown committed
40
#ifndef EMBEDDED_LIBRARY
41
bool Protocol::net_store_data(const uchar *from, size_t length)
unknown's avatar
SCRUM  
unknown committed
42
#else
43
bool Protocol_binary::net_store_data(const uchar *from, size_t length)
unknown's avatar
SCRUM  
unknown committed
44
#endif
unknown's avatar
SCRUM  
unknown committed
45 46
{
  ulong packet_length=packet->length();
unknown's avatar
unknown committed
47 48 49 50 51 52
  /* 
     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))
unknown's avatar
SCRUM  
unknown committed
53
    return 1;
54
  uchar *to= net_store_length((uchar*) packet->ptr()+packet_length, length);
unknown's avatar
SCRUM  
unknown committed
55
  memcpy(to,from,length);
56
  packet->length((uint) (to+length-(uchar*) packet->ptr()));
unknown's avatar
SCRUM  
unknown committed
57 58 59 60
  return 0;
}


61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
/*
  net_store_data() - extended version with character set conversion.
  
  It is optimized for short strings whose length after
  conversion is garanteed to be less than 251, which accupies
  exactly one byte to store length. It allows not to use
  the "convert" member as a temporary buffer, conversion
  is done directly to the "packet" member.
  The limit 251 is good enough to optimize send_fields()
  because column, table, database names fit into this limit.
*/

#ifndef EMBEDDED_LIBRARY
bool Protocol::net_store_data(const uchar *from, size_t length,
                              CHARSET_INFO *from_cs, CHARSET_INFO *to_cs)
{
  uint dummy_errors;
  /* Calculate maxumum possible result length */
  size_t conv_length= to_cs->mbmaxlen * length / from_cs->mbminlen;
  ulong packet_length, new_length;
  char *length_pos, *to;

  if (conv_length > 250)
  {
    /*
      For strings with conv_length greater than 250 bytes
      we don't know how many bytes we will need to store length: one or two,
      because we don't know result length until conversion is done.
      For example, when converting from utf8 (mbmaxlen=3) to latin1,
      conv_length=300 means that the result length can vary between 100 to 300.
      length=100 needs one byte, length=300 needs to bytes.
      
      Thus conversion directly to "packet" is not worthy.
      Let's use "convert" as a temporary buffer.
    */
    return (convert->copy((const char*) from, length, from_cs, to_cs,
                          &dummy_errors) ||
            net_store_data((const uchar*) convert->ptr(), convert->length()));
  }

  packet_length= packet->length();
  new_length= packet_length + conv_length + 1;

  if (new_length > packet->alloced_length() && packet->realloc(new_length))
    return 1;

  length_pos= (char*) packet->ptr() + packet_length;
  to= length_pos + 1;

  to+= copy_and_convert(to, conv_length, to_cs,
                        (const char*) from, length, from_cs, &dummy_errors);

  net_store_length((uchar*) length_pos, to - length_pos - 1);
  packet->length((uint) (to - packet->ptr()));
  return 0;
}
#endif


unknown's avatar
unknown committed
120 121 122 123
/**
  Send a error string to client.

  Design note:
124

unknown's avatar
unknown committed
125 126 127
  net_printf_error and net_send_error are low-level functions
  that shall be used only when a new connection is being
  established or at server startup.
128

unknown's avatar
unknown committed
129 130 131
  For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
  critical that every error that can be intercepted is issued in one
  place only, my_message_sql.
132 133 134 135 136 137 138 139

  @param thd Thread handler
  @param sql_errno The error code to send
  @param err A pointer to the error message

  @return
    @retval FALSE The message was sent to the client
    @retval TRUE An error occurred and the message wasn't sent properly
140
*/
141 142

bool net_send_error(THD *thd, uint sql_errno, const char *err)
143
{
144
  DBUG_ENTER("net_send_error");
145

146
  DBUG_ASSERT(!thd->spcont);
147 148
  DBUG_ASSERT(sql_errno);
  DBUG_ASSERT(err && err[0]);
149

150
  DBUG_PRINT("enter",("sql_errno: %d  err: %s", sql_errno, err));
151
  bool error;
152

153 154 155 156 157
  /*
    It's one case when we can push an error even though there
    is an OK or EOF already.
  */
  thd->main_da.can_overwrite_status= TRUE;
158

159 160
  /* Abort multi-result sets */
  thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
unknown's avatar
unknown committed
161

162
  error= net_send_error_packet(thd, sql_errno, err);
163

164
  thd->main_da.can_overwrite_status= FALSE;
165

166
  DBUG_RETURN(error);
167 168
}

unknown's avatar
unknown committed
169
/**
170 171
  Return ok to the client.

unknown's avatar
unknown committed
172 173 174 175 176 177 178 179 180 181 182 183 184
  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.

  @param thd		   Thread handler
185 186
  @param server_status     The server status
  @param total_warn_count  Total number of warnings
unknown's avatar
unknown committed
187 188 189
  @param affected_rows	   Number of rows changed by statement
  @param id		   Auto_increment id for first row (if used)
  @param message	   Message to send to the client (Used by mysql_status)
190 191 192 193 194
 
  @return
    @retval FALSE The message was successfully sent
    @retval TRUE An error occurred and the messages wasn't sent properly

unknown's avatar
unknown committed
195
*/
196

197
#ifndef EMBEDDED_LIBRARY
198
bool
199 200 201
net_send_ok(THD *thd,
            uint server_status, uint total_warn_count,
            ha_rows affected_rows, ulonglong id, const char *message)
202 203
{
  NET *net= &thd->net;
204
  uchar buff[MYSQL_ERRMSG_SIZE+10],*pos;
205
  bool error= FALSE;
206
  DBUG_ENTER("net_send_ok");
207

208
  if (! net->vio)	// hack for re-parsing queries
209
  {
210
    DBUG_PRINT("info", ("vio present: NO"));
211
    DBUG_RETURN(FALSE);
212
  }
213

214
  buff[0]=0;					// No fields
215 216
  pos=net_store_length(buff+1,affected_rows);
  pos=net_store_length(pos, id);
217 218
  if (thd->client_capabilities & CLIENT_PROTOCOL_41)
  {
219 220 221 222
    DBUG_PRINT("info",
	       ("affected_rows: %lu  id: %lu  status: %u  warning_count: %u",
		(ulong) affected_rows,		
		(ulong) id,
223 224 225
		(uint) (server_status & 0xffff),
		(uint) total_warn_count));
    int2store(pos, server_status);
226 227 228
    pos+=2;

    /* We can only return up to 65535 warnings in two bytes */
229
    uint tmp= min(total_warn_count, 65535);
230 231 232 233 234
    int2store(pos, tmp);
    pos+= 2;
  }
  else if (net->return_status)			// For 4.0 protocol
  {
235
    int2store(pos, server_status);
236 237
    pos+=2;
  }
238 239 240
  thd->main_da.can_overwrite_status= TRUE;

  if (message && message[0])
241
    pos= net_store_data(pos, (uchar*) message, strlen(message));
242 243 244
  error= my_net_write(net, buff, (size_t) (pos-buff));
  if (!error)
    error= net_flush(net);
245 246

  thd->main_da.can_overwrite_status= FALSE;
247
  DBUG_PRINT("info", ("OK sent, so no more error sending allowed"));
248

249
  DBUG_RETURN(error);
250 251
}

252
static uchar eof_buff[1]= { (uchar) 254 };      /* Marker for end of fields */
253

unknown's avatar
unknown committed
254 255
/**
  Send eof (= end of result set) to the client.
256

unknown's avatar
unknown committed
257
  The eof packet has the following structure:
258

unknown's avatar
unknown committed
259 260 261 262
  - 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_MORE_RESULTS_EXISTS.
263

unknown's avatar
unknown committed
264 265 266
  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.
267

unknown's avatar
unknown committed
268
  @param thd		Thread handler
269 270 271 272 273 274
  @param server_status The server status
  @param total_warn_count Total number of warnings

  @return
    @retval FALSE The message was successfully sent
    @retval TRUE An error occurred and the message wasn't sent properly
275 276
*/    

277
bool
278
net_send_eof(THD *thd, uint server_status, uint total_warn_count)
279 280
{
  NET *net= &thd->net;
281
  bool error= FALSE;
282 283
  DBUG_ENTER("net_send_eof");
  /* Set to TRUE if no active vio, to work well in case of --init-file */
284
  if (net->vio != 0)
285
  {
286
    thd->main_da.can_overwrite_status= TRUE;
287 288 289
    error= write_eof_packet(thd, net, server_status, total_warn_count);
    if (!error)
      error= net_flush(net);
290
    thd->main_da.can_overwrite_status= FALSE;
291
    DBUG_PRINT("info", ("EOF sent, so no more error sending allowed"));
292
  }
293
  DBUG_RETURN(error);
294
}
295

296

unknown's avatar
unknown committed
297
/**
298 299
  Format EOF packet according to the current protocol and
  write it to the network output buffer.
300 301 302 303 304 305 306 307 308 309

  @param thd The thread handler
  @param net The network handler
  @param server_status The server status
  @param total_warn_count The number of warnings


  @return
    @retval FALSE The message was sent successfully
    @retval TRUE An error occurred and the messages wasn't sent properly
310 311
*/

312
static bool write_eof_packet(THD *thd, NET *net,
313 314
                             uint server_status,
                             uint total_warn_count)
315
{
316
  bool error;
317 318 319 320 321 322 323
  if (thd->client_capabilities & CLIENT_PROTOCOL_41)
  {
    uchar buff[5];
    /*
      Don't send warn count during SP execution, as the warn_list
      is cleared between substatements, and mysqltest gets confused
    */
324
    uint tmp= min(total_warn_count, 65535);
325 326 327 328 329 330 331 332
    buff[0]= 254;
    int2store(buff+1, tmp);
    /*
      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)
333 334
      server_status&= ~SERVER_MORE_RESULTS_EXISTS;
    int2store(buff + 3, server_status);
335
    error= my_net_write(net, buff, 5);
336 337
  }
  else
338 339 340
    error= my_net_write(net, eof_buff, 1);
  
  return error;
341 342
}

unknown's avatar
unknown committed
343 344
/**
  Please client to send scrambled_password in old format.
345
     
unknown's avatar
unknown committed
346 347 348
  @param thd thread handle

  @retval
349
    0  ok
unknown's avatar
unknown committed
350
  @retval
351 352 353 354 355 356
   !0  error
*/

bool send_old_password_request(THD *thd)
{
  NET *net= &thd->net;
357
  return my_net_write(net, eof_buff, 1) || net_flush(net);
358 359
}

360

361 362 363 364 365 366 367 368 369 370 371
/**
  @param thd Thread handler
  @param sql_errno The error code to send
  @param err A pointer to the error message

  @return
   @retval FALSE The message was successfully sent
   @retval TRUE  An error occurred and the messages wasn't sent properly
*/

bool net_send_error_packet(THD *thd, uint sql_errno, const char *err)
372 373 374
{
  NET *net= &thd->net;
  uint length;
375 376 377
  /*
    buff[]: sql_errno:2 + ('#':1 + SQLSTATE_LENGTH:5) + MYSQL_ERRMSG_SIZE:512
  */
378
  uchar buff[2+1+SQLSTATE_LENGTH+MYSQL_ERRMSG_SIZE], *pos;
379 380 381 382 383 384 385 386 387 388

  DBUG_ENTER("send_error_packet");

  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);
    }
389
    DBUG_RETURN(FALSE);
390 391 392 393 394 395 396 397 398 399
  }

  if (net->return_errno)
  {				// new client code; Add errno before message
    int2store(buff,sql_errno);
    pos= buff+2;
    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
    {
      /* The first # is to make the protocol backward compatible */
      buff[2]= '#';
400
      pos= (uchar*) strmov((char*) buff+3, mysql_errno_to_sqlstate(sql_errno));
401
    }
402 403 404
    length= (uint) (strmake((char*) pos, err, MYSQL_ERRMSG_SIZE-1) -
                    (char*) buff);
    err= (char*) buff;
405 406 407 408 409 410
  }
  else
  {
    length=(uint) strlen(err);
    set_if_smaller(length,MYSQL_ERRMSG_SIZE-1);
  }
411
  DBUG_RETURN(net_write_command(net,(uchar) 255, (uchar*) "", 0, (uchar*) err,
412
                         length));
413 414
}

unknown's avatar
unknown committed
415
#endif /* EMBEDDED_LIBRARY */
416

unknown's avatar
unknown committed
417
/**
418 419 420
  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.
unknown's avatar
unknown committed
421

422
  uint is used as agrument type because of MySQL type conventions:
unknown's avatar
unknown committed
423 424 425
  - uint for 0..65536
  - ulong for 0..4294967296
  - ulonglong for bigger numbers.
426 427
*/

428
static uchar *net_store_length_fast(uchar *packet, uint length)
429 430 431 432
{
  if (length < 251)
  {
    *packet=(uchar) length;
433
    return packet+1;
434 435 436
  }
  *packet++=252;
  int2store(packet,(uint) length);
437
  return packet+2;
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 482 483 484 485 486 487 488 489 490 491
/**
  Send the status of the current statement execution over network.

  @param  thd   in fact, carries two parameters, NET for the transport and
                Diagnostics_area as the source of status information.

  In MySQL, there are two types of SQL statements: those that return
  a result set and those that return status information only.

  If a statement returns a result set, it consists of 3 parts:
  - result set meta-data
  - variable number of result set rows (can be 0)
  - followed and terminated by EOF or ERROR packet

  Once the  client has seen the meta-data information, it always
  expects an EOF or ERROR to terminate the result set. If ERROR is
  received, the result set rows are normally discarded (this is up
  to the client implementation, libmysql at least does discard them).
  EOF, on the contrary, means "successfully evaluated the entire
  result set". Since we don't know how many rows belong to a result
  set until it's evaluated, EOF/ERROR is the indicator of the end
  of the row stream. Note, that we can not buffer result set rows
  on the server -- there may be an arbitrary number of rows. But
  we do buffer the last packet (EOF/ERROR) in the Diagnostics_area and
  delay sending it till the very end of execution (here), to be able to
  change EOF to an ERROR if commit failed or some other error occurred
  during the last cleanup steps taken after execution.

  A statement that does not return a result set doesn't send result
  set meta-data either. Instead it returns one of:
  - OK packet
  - ERROR packet.
  Similarly to the EOF/ERROR of the previous statement type, OK/ERROR
  packet is "buffered" in the diagnostics area and sent to the client
  in the end of statement.

  @pre  The diagnostics area is assigned or disabled. It can not be empty
        -- we assume that every SQL statement or COM_* command
        generates OK, ERROR, or EOF status.

  @post The status information is encoded to protocol format and sent to the
        client.

  @return We conventionally return void, since the only type of error
          that can happen here is a NET (transport) error, and that one
          will become visible when we attempt to read from the NET the
          next command.
          Diagnostics_area::is_sent is set for debugging purposes only.
*/

void net_end_statement(THD *thd)
{
492
  DBUG_ENTER("net_end_statement");
493 494 495 496 497 498
  DBUG_ASSERT(! thd->main_da.is_sent);

  /* Can not be true, but do not take chances in production. */
  if (thd->main_da.is_sent)
    return;

499 500
  bool error= FALSE;

501 502 503
  switch (thd->main_da.status()) {
  case Diagnostics_area::DA_ERROR:
    /* The query failed, send error to log and abort bootstrap. */
504 505 506
    error= net_send_error(thd,
                          thd->main_da.sql_errno(),
                          thd->main_da.message());
507 508
    break;
  case Diagnostics_area::DA_EOF:
509 510 511
    error= net_send_eof(thd,
                        thd->main_da.server_status(),
                        thd->main_da.total_warn_count());
512 513
    break;
  case Diagnostics_area::DA_OK:
514 515 516 517 518 519
    error= net_send_ok(thd,
                       thd->main_da.server_status(),
                       thd->main_da.total_warn_count(),
                       thd->main_da.affected_rows(),
                       thd->main_da.last_insert_id(),
                       thd->main_da.message());
520 521 522 523 524 525
    break;
  case Diagnostics_area::DA_DISABLED:
    break;
  case Diagnostics_area::DA_EMPTY:
  default:
    DBUG_ASSERT(0);
526 527
    error= net_send_ok(thd, thd->server_status, thd->total_warn_count,
                       0, 0, NULL);
528 529
    break;
  }
530 531
  if (!error)
    thd->main_da.is_sent= TRUE;
532
  DBUG_VOID_RETURN;
533 534
}

535 536

/****************************************************************************
537 538
  Functions used by the protocol functions (like net_send_ok) to store
  strings and numbers in the header result packet.
539 540 541 542
****************************************************************************/

/* The following will only be used for short strings < 65K */

543
uchar *net_store_data(uchar *to, const uchar *from, size_t length)
544
{
545
  to=net_store_length_fast(to,length);
546 547 548 549
  memcpy(to,from,length);
  return to+length;
}

550
uchar *net_store_data(uchar *to,int32 from)
551 552 553
{
  char buff[20];
  uint length=(uint) (int10_to_str(from,buff,10)-buff);
554
  to=net_store_length_fast(to,length);
555 556 557 558
  memcpy(to,buff,length);
  return to+length;
}

559
uchar *net_store_data(uchar *to,longlong from)
560 561 562
{
  char buff[22];
  uint length=(uint) (longlong10_to_str(from,buff,10)-buff);
563
  to=net_store_length_fast(to,length);
564 565 566 567 568 569 570 571 572 573 574 575 576
  memcpy(to,buff,length);
  return to+length;
}


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

void Protocol::init(THD *thd_arg)
{
  thd=thd_arg;
  packet= &thd->packet;
577
  convert= &thd->convert_buffer;
578
#ifndef DBUG_OFF
579 580 581 582
  field_types= 0;
#endif
}

583 584 585 586 587 588
/**
  Finish the result set with EOF packet, as is expected by the client,
  if there is an error evaluating the next row and a continue handler
  for the error.
*/

589
void Protocol::end_partial_result_set(THD *thd_arg)
590
{
591 592
  net_send_eof(thd_arg, thd_arg->server_status,
               0 /* no warnings, we're inside SP */);
593 594
}

595

596 597 598
bool Protocol::flush()
{
#ifndef EMBEDDED_LIBRARY
599 600 601 602 603
  bool error;
  thd->main_da.can_overwrite_status= TRUE;
  error= net_flush(&thd->net);
  thd->main_da.can_overwrite_status= FALSE;
  return error;
604 605 606 607 608
#else
  return 0;
#endif
}

unknown's avatar
unknown committed
609 610 611
#ifndef EMBEDDED_LIBRARY

/**
612 613
  Send name and type of result to client.

unknown's avatar
unknown committed
614
  Sum fields has table name empty and field_name.
615

unknown's avatar
unknown committed
616 617 618 619 620 621
  @param THD		Thread data object
  @param list	        List of items to send to client
  @param flag	        Bit mask with the following functions:
                        - 1 send number of rows
                        - 2 send default values
                        - 4 don't write eof packet
622

unknown's avatar
unknown committed
623
  @retval
624
    0	ok
unknown's avatar
unknown committed
625 626 627
  @retval
    1	Error  (Note that in this case the error is not sent to the
    client)
628
*/
unknown's avatar
unknown committed
629
bool Protocol::send_fields(List<Item> *list, uint flags)
630 631 632
{
  List_iterator_fast<Item> it(*list);
  Item *item;
633
  uchar buff[80];
unknown's avatar
unknown committed
634
  String tmp((char*) buff,sizeof(buff),&my_charset_bin);
unknown's avatar
unknown committed
635
  Protocol_text prot(thd);
636
  String *local_packet= prot.storage_packet();
637
  CHARSET_INFO *thd_charset= thd->variables.character_set_results;
638 639
  DBUG_ENTER("send_fields");

640
  if (flags & SEND_NUM_ROWS)
641
  {				// Packet with number of elements
642
    uchar *pos= net_store_length(buff, list->elements);
643 644
    if (my_net_write(&thd->net, buff, (size_t) (pos-buff)))
      DBUG_RETURN(1);
645 646
  }

647
#ifndef DBUG_OFF
648 649 650 651 652 653 654 655
  field_types= (enum_field_types*) thd->alloc(sizeof(field_types) *
					      list->elements);
  uint count= 0;
#endif

  while ((item=it++))
  {
    char *pos;
656
    CHARSET_INFO *cs= system_charset_info;
657 658
    Send_field field;
    item->make_field(&field);
659 660 661 662 663

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

664 665 666 667
    prot.prepare_for_resend();

    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
    {
668
      if (prot.store(STRING_WITH_LEN("def"), cs, thd_charset) ||
669 670
	  prot.store(field.db_name, (uint) strlen(field.db_name),
		     cs, thd_charset) ||
671
	  prot.store(field.table_name, (uint) strlen(field.table_name),
672
		     cs, thd_charset) ||
673
	  prot.store(field.org_table_name, (uint) strlen(field.org_table_name),
674
		     cs, thd_charset) ||
675
	  prot.store(field.col_name, (uint) strlen(field.col_name),
676
		     cs, thd_charset) ||
677
	  prot.store(field.org_col_name, (uint) strlen(field.org_col_name),
678
		     cs, thd_charset) ||
679
	  local_packet->realloc(local_packet->length()+12))
680
	goto err;
681
      /* Store fixed length fields */
682
      pos= (char*) local_packet->ptr()+local_packet->length();
683
      *pos++= 12;				// Length of packed fields
unknown's avatar
unknown committed
684
      if (item->collation.collation == &my_charset_bin || thd_charset == NULL)
685 686
      {
        /* No conversion */
unknown's avatar
unknown committed
687
        int2store(pos, field.charsetnr);
688 689
        int4store(pos+2, field.length);
      }
unknown's avatar
unknown committed
690
      else
691 692
      {
        /* With conversion */
693 694
        ulonglong max_length;
        uint32 field_length;
695
        int2store(pos, thd_charset->number);
696 697 698 699 700 701 702 703 704
        /*
          For TEXT/BLOB columns, field_length describes the maximum data
          length in bytes. There is no limit to the number of characters
          that a TEXT column can store, as long as the data fits into
          the designated space.
          For the rest of textual columns, field_length is evaluated as
          char_count * mbmaxlen, where character count is taken from the
          definition of the column. In other words, the maximum number
          of characters here is limited by the column definition.
705 706 707 708 709 710 711

          When one has a LONG TEXT column with a single-byte
          character set, and the connection character set is multi-byte, the
          client may get fields longer than UINT_MAX32, due to
          <character set column> -> <character set connection> conversion.
          In that case column max length does not fit into the 4 bytes
          reserved for it in the protocol.
712
        */
713 714 715 716 717
        max_length= (field.type >= MYSQL_TYPE_TINY_BLOB &&
                     field.type <= MYSQL_TYPE_BLOB) ?
                     field.length / item->collation.collation->mbminlen :
                     field.length / item->collation.collation->mbmaxlen;
        max_length*= thd_charset->mbmaxlen;
718 719
        field_length= (max_length > UINT_MAX32) ? 
          UINT_MAX32 : (uint32) max_length;
720
        int4store(pos + 2, field_length);
721
      }
722 723 724
      pos[6]= field.type;
      int2store(pos+7,field.flags);
      pos[9]= (char) field.decimals;
725
      pos[10]= 0;				// For the future
726 727
      pos[11]= 0;				// For the future
      pos+= 12;
728 729 730
    }
    else
    {
731
      if (prot.store(field.table_name, (uint) strlen(field.table_name),
732
		     cs, thd_charset) ||
733
	  prot.store(field.col_name, (uint) strlen(field.col_name),
734
		     cs, thd_charset) ||
735
	  local_packet->realloc(local_packet->length()+10))
736
	goto err;
737
      pos= (char*) local_packet->ptr()+local_packet->length();
738 739

#ifdef TO_BE_DELETED_IN_6
740 741 742 743 744 745 746 747 748 749 750 751
      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
752
#endif
753 754 755 756 757 758 759 760 761 762
      {
	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;
      }
763
    }
764
    local_packet->length((uint) (pos - local_packet->ptr()));
765
    if (flags & SEND_DEFAULTS)
766 767
      item->send(&prot, &tmp);			// Send default value
    if (prot.write())
768
      DBUG_RETURN(1);
769
#ifndef DBUG_OFF
770 771 772 773
    field_types[count++]= field.type;
#endif
  }

774
  if (flags & SEND_EOF)
775 776 777 778 779 780
  {
    /*
      Mark the end of meta-data result set, and store thd->server_status,
      to show that there is no cursor.
      Send no warning information, as it will be sent at statement end.
    */
781 782 783
    if (write_eof_packet(thd, &thd->net, thd->server_status,
                         thd->total_warn_count))
      DBUG_RETURN(1);
784
  }
785 786 787
  DBUG_RETURN(prepare_for_send(list));

err:
unknown's avatar
unknown committed
788 789
  my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
             MYF(0));	/* purecov: inspected */
790 791 792
  DBUG_RETURN(1);				/* purecov: inspected */
}

793

794 795 796
bool Protocol::write()
{
  DBUG_ENTER("Protocol::write");
797 798
  DBUG_RETURN(my_net_write(&thd->net, (uchar*) packet->ptr(),
                           packet->length()));
799
}
unknown's avatar
SCRUM  
unknown committed
800 801 802
#endif /* EMBEDDED_LIBRARY */


unknown's avatar
unknown committed
803 804
/**
  Send \\0 end terminated string.
805

unknown's avatar
unknown committed
806
  @param from	NullS or \\0 terminated string
807

unknown's avatar
unknown committed
808
  @note
809 810
    In most cases one should use store(from, length) instead of this function

unknown's avatar
unknown committed
811
  @retval
812
    0		ok
unknown's avatar
unknown committed
813
  @retval
814 815 816
    1		error
*/

817
bool Protocol::store(const char *from, CHARSET_INFO *cs)
818 819 820 821
{
  if (!from)
    return store_null();
  uint length= strlen(from);
822
  return store(from, length, cs);
823 824 825
}


unknown's avatar
unknown committed
826 827
/**
  Send a set of strings as one long string with ',' in between.
828 829 830 831 832
*/

bool Protocol::store(I_List<i_string>* str_list)
{
  char buf[256];
unknown's avatar
unknown committed
833
  String tmp(buf, sizeof(buf), &my_charset_bin);
834
  uint32 len;
835 836 837
  I_List_iterator<i_string> it(*str_list);
  i_string* s;

838
  tmp.length(0);
839 840 841
  while ((s=it++))
  {
    tmp.append(s->ptr);
842
    tmp.append(',');
843
  }
844 845
  if ((len= tmp.length()))
    len--;					// Remove last ','
846
  return store((char*) tmp.ptr(), len,  tmp.charset());
847 848 849 850 851 852 853 854 855 856 857
}


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

unknown's avatar
SCRUM  
unknown committed
858
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
859
void Protocol_text::prepare_for_resend()
860 861
{
  packet->length(0);
862
#ifndef DBUG_OFF
863 864 865 866
  field_pos= 0;
#endif
}

unknown's avatar
unknown committed
867
bool Protocol_text::store_null()
868
{
869
#ifndef DBUG_OFF
870 871 872
  field_pos++;
#endif
  char buff[1];
unknown's avatar
unknown committed
873
  buff[0]= (char)251;
874
  return packet->append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
875
}
unknown's avatar
SCRUM  
unknown committed
876
#endif
877

878

unknown's avatar
unknown committed
879
/**
880 881 882 883
  Auxilary function to convert string to the given character set
  and store in network buffer.
*/

884
bool Protocol::store_string_aux(const char *from, size_t length,
885 886 887 888 889 890 891
                                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)
  {
892 893
    /* Store with conversion */
    return net_store_data((uchar*) from, length, fromcs, tocs);
894
  }
895
  /* Store without conversion */
896
  return net_store_data((uchar*) from, length);
897 898 899
}


900 901
bool Protocol_text::store(const char *from, size_t length,
                          CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
902
{
903
#ifndef DBUG_OFF
904
  DBUG_ASSERT(field_types == 0 ||
905
	      field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
unknown's avatar
unknown committed
906
              field_types[field_pos] == MYSQL_TYPE_BIT ||
unknown's avatar
unknown committed
907
              field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL ||
908 909
	      (field_types[field_pos] >= MYSQL_TYPE_ENUM &&
	       field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
910 911
  field_pos++;
#endif
912
  return store_string_aux(from, length, fromcs, tocs);
913 914 915
}


916
bool Protocol_text::store(const char *from, size_t length,
917
                          CHARSET_INFO *fromcs)
918
{
919
  CHARSET_INFO *tocs= this->thd->variables.character_set_results;
920
#ifndef DBUG_OFF
921
  DBUG_PRINT("info", ("Protocol_text::store field %u (%u): %.*s", field_pos,
unknown's avatar
unknown committed
922
                      field_count, (int) length, (length == 0? "" : from)));
923
  DBUG_ASSERT(field_pos < field_count);
924 925
  DBUG_ASSERT(field_types == 0 ||
	      field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
unknown's avatar
unknown committed
926
              field_types[field_pos] == MYSQL_TYPE_BIT ||
unknown's avatar
unknown committed
927
              field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL ||
928
              field_types[field_pos] == MYSQL_TYPE_NEWDATE ||
929 930 931 932
	      (field_types[field_pos] >= MYSQL_TYPE_ENUM &&
	       field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
  field_pos++;
#endif
933
  return store_string_aux(from, length, fromcs, tocs);
934 935 936
}


unknown's avatar
unknown committed
937
bool Protocol_text::store_tiny(longlong from)
938
{
939
#ifndef DBUG_OFF
unknown's avatar
unknown committed
940 941
  DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TINY);
  field_pos++;
942 943
#endif
  char buff[20];
944 945
  return net_store_data((uchar*) buff,
			(size_t) (int10_to_str((int) from, buff, -10) - buff));
946 947
}

948

unknown's avatar
unknown committed
949
bool Protocol_text::store_short(longlong from)
950
{
951
#ifndef DBUG_OFF
952
  DBUG_ASSERT(field_types == 0 ||
unknown's avatar
unknown committed
953
	      field_types[field_pos] == MYSQL_TYPE_YEAR ||
unknown's avatar
unknown committed
954 955
	      field_types[field_pos] == MYSQL_TYPE_SHORT);
  field_pos++;
956 957
#endif
  char buff[20];
958 959 960
  return net_store_data((uchar*) buff,
			(size_t) (int10_to_str((int) from, buff, -10) -
                                  buff));
961 962
}

963

unknown's avatar
unknown committed
964
bool Protocol_text::store_long(longlong from)
965
{
966
#ifndef DBUG_OFF
unknown's avatar
unknown committed
967 968 969 970
  DBUG_ASSERT(field_types == 0 ||
              field_types[field_pos] == MYSQL_TYPE_INT24 ||
              field_types[field_pos] == MYSQL_TYPE_LONG);
  field_pos++;
971 972
#endif
  char buff[20];
973 974 975
  return net_store_data((uchar*) buff,
			(size_t) (int10_to_str((long int)from, buff,
                                               (from <0)?-10:10)-buff));
976 977 978
}


unknown's avatar
unknown committed
979
bool Protocol_text::store_longlong(longlong from, bool unsigned_flag)
980
{
981
#ifndef DBUG_OFF
982
  DBUG_ASSERT(field_types == 0 ||
unknown's avatar
unknown committed
983 984
	      field_types[field_pos] == MYSQL_TYPE_LONGLONG);
  field_pos++;
985 986
#endif
  char buff[22];
987 988 989 990
  return net_store_data((uchar*) buff,
			(size_t) (longlong10_to_str(from,buff,
                                                    unsigned_flag ? 10 : -10)-
                                  buff));
991 992 993
}


unknown's avatar
unknown committed
994
bool Protocol_text::store_decimal(const my_decimal *d)
unknown's avatar
unknown committed
995
{
996
#ifndef DBUG_OFF
unknown's avatar
unknown committed
997 998 999 1000
  DBUG_ASSERT(field_types == 0 ||
              field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
  field_pos++;
#endif
1001 1002 1003
  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);
1004
  return net_store_data((uchar*) str.ptr(), str.length());
unknown's avatar
unknown committed
1005 1006 1007
}


unknown's avatar
unknown committed
1008
bool Protocol_text::store(float from, uint32 decimals, String *buffer)
1009
{
1010
#ifndef DBUG_OFF
1011
  DBUG_ASSERT(field_types == 0 ||
unknown's avatar
unknown committed
1012 1013
	      field_types[field_pos] == MYSQL_TYPE_FLOAT);
  field_pos++;
1014
#endif
1015
  buffer->set_real((double) from, decimals, thd->charset());
1016
  return net_store_data((uchar*) buffer->ptr(), buffer->length());
1017 1018
}

1019

unknown's avatar
unknown committed
1020
bool Protocol_text::store(double from, uint32 decimals, String *buffer)
1021
{
1022
#ifndef DBUG_OFF
1023
  DBUG_ASSERT(field_types == 0 ||
unknown's avatar
unknown committed
1024 1025
	      field_types[field_pos] == MYSQL_TYPE_DOUBLE);
  field_pos++;
1026
#endif
1027
  buffer->set_real(from, decimals, thd->charset());
1028
  return net_store_data((uchar*) buffer->ptr(), buffer->length());
1029 1030 1031
}


unknown's avatar
unknown committed
1032
bool Protocol_text::store(Field *field)
1033
{
1034 1035
  if (field->is_null())
    return store_null();
1036
#ifndef DBUG_OFF
1037 1038 1039
  field_pos++;
#endif
  char buff[MAX_FIELD_WIDTH];
1040
  String str(buff,sizeof(buff), &my_charset_bin);
1041
  CHARSET_INFO *tocs= this->thd->variables.character_set_results;
unknown's avatar
unknown committed
1042
#ifndef DBUG_OFF
1043 1044 1045 1046 1047
  TABLE *table= field->table;
  my_bitmap_map *old_map= 0;
  if (table->file)
    old_map= dbug_tmp_use_all_columns(table, table->read_set);
#endif
1048

1049
  field->val_str(&str);
unknown's avatar
unknown committed
1050
#ifndef DBUG_OFF
1051 1052 1053 1054
  if (old_map)
    dbug_tmp_restore_column_map(table->read_set, old_map);
#endif

1055
  return store_string_aux(str.ptr(), str.length(), str.charset(), tocs);
1056 1057 1058
}


unknown's avatar
unknown committed
1059 1060
/**
  @todo
1061 1062
    Second_part format ("%06") needs to change when 
    we support 0-6 decimals for time.
unknown's avatar
unknown committed
1063 1064
*/

1065
bool Protocol_text::store(MYSQL_TIME *tm)
1066
{
1067
#ifndef DBUG_OFF
1068
  DBUG_ASSERT(field_types == 0 ||
1069 1070 1071
	      field_types[field_pos] == MYSQL_TYPE_DATETIME ||
	      field_types[field_pos] == MYSQL_TYPE_TIMESTAMP);
  field_pos++;
1072 1073
#endif
  char buff[40];
1074 1075 1076 1077 1078 1079 1080 1081 1082
  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)
1083 1084 1085
    length+= my_sprintf(buff+length,(buff+length, ".%06d",
                                     (int)tm->second_part));
  return net_store_data((uchar*) buff, length);
1086 1087 1088
}


1089
bool Protocol_text::store_date(MYSQL_TIME *tm)
1090
{
1091
#ifndef DBUG_OFF
1092
  DBUG_ASSERT(field_types == 0 ||
unknown's avatar
unknown committed
1093 1094
	      field_types[field_pos] == MYSQL_TYPE_DATE);
  field_pos++;
1095
#endif
1096
  char buff[MAX_DATE_STRING_REP_LENGTH];
1097 1098
  size_t length= my_date_to_str(tm, buff);
  return net_store_data((uchar*) buff, length);
1099 1100 1101
}


unknown's avatar
unknown committed
1102 1103
/**
  @todo 
1104 1105
    Second_part format ("%06") needs to change when 
    we support 0-6 decimals for time.
unknown's avatar
unknown committed
1106 1107
*/

1108
bool Protocol_text::store_time(MYSQL_TIME *tm)
1109
{
1110
#ifndef DBUG_OFF
1111
  DBUG_ASSERT(field_types == 0 ||
unknown's avatar
unknown committed
1112 1113
	      field_types[field_pos] == MYSQL_TYPE_TIME);
  field_pos++;
1114 1115
#endif
  char buff[40];
1116
  uint length;
1117
  uint day= (tm->year || tm->month) ? 0 : tm->day;
1118 1119 1120 1121 1122 1123 1124
  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));
1125
  return net_store_data((uchar*) buff, length);
1126 1127 1128 1129 1130
}


/****************************************************************************
  Functions to handle the binary protocol used with prepared statements
unknown's avatar
unknown committed
1131 1132 1133

  Data format:

1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
   [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
1146 1147
****************************************************************************/

unknown's avatar
unknown committed
1148
bool Protocol_binary::prepare_for_send(List<Item> *item_list)
1149
{
unknown's avatar
SCRUM  
unknown committed
1150
  Protocol::prepare_for_send(item_list);
unknown's avatar
unknown committed
1151 1152
  bit_fields= (field_count+9)/8;
  if (packet->alloc(bit_fields+1))
1153 1154 1155 1156 1157 1158
    return 1;
  /* prepare_for_resend will be called after this one */
  return 0;
}


unknown's avatar
unknown committed
1159
void Protocol_binary::prepare_for_resend()
1160
{
unknown's avatar
unknown committed
1161
  packet->length(bit_fields+1);
1162
  bzero((uchar*) packet->ptr(), 1+bit_fields);
1163 1164 1165 1166
  field_pos=0;
}


1167
bool Protocol_binary::store(const char *from, size_t length,
1168
                            CHARSET_INFO *fromcs)
1169
{
1170
  CHARSET_INFO *tocs= thd->variables.character_set_results;
1171
  field_pos++;
1172
  return store_string_aux(from, length, fromcs, tocs);
1173 1174
}

1175
bool Protocol_binary::store(const char *from, size_t length,
1176
                            CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
1177 1178
{
  field_pos++;
1179
  return store_string_aux(from, length, fromcs, tocs);
1180 1181
}

unknown's avatar
unknown committed
1182
bool Protocol_binary::store_null()
1183
{
unknown's avatar
unknown committed
1184
  uint offset= (field_pos+2)/8+1, bit= (1 << ((field_pos+2) & 7));
1185 1186 1187 1188 1189 1190 1191 1192
  /* 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;
}


unknown's avatar
unknown committed
1193
bool Protocol_binary::store_tiny(longlong from)
1194 1195 1196 1197
{
  char buff[1];
  field_pos++;
  buff[0]= (uchar) from;
1198
  return packet->append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
1199 1200 1201
}


unknown's avatar
unknown committed
1202
bool Protocol_binary::store_short(longlong from)
1203 1204
{
  field_pos++;
1205
  char *to= packet->prep_append(2, PACKET_BUFFER_EXTRA_ALLOC);
1206 1207 1208 1209 1210 1211 1212
  if (!to)
    return 1;
  int2store(to, (int) from);
  return 0;
}


unknown's avatar
unknown committed
1213
bool Protocol_binary::store_long(longlong from)
1214 1215
{
  field_pos++;
1216
  char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
1217 1218 1219 1220 1221 1222 1223
  if (!to)
    return 1;
  int4store(to, from);
  return 0;
}


unknown's avatar
unknown committed
1224
bool Protocol_binary::store_longlong(longlong from, bool unsigned_flag)
1225 1226
{
  field_pos++;
1227
  char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
1228 1229 1230 1231 1232 1233
  if (!to)
    return 1;
  int8store(to, from);
  return 0;
}

unknown's avatar
unknown committed
1234
bool Protocol_binary::store_decimal(const my_decimal *d)
unknown's avatar
unknown committed
1235
{
1236
#ifndef DBUG_OFF
unknown's avatar
unknown committed
1237 1238 1239 1240
  DBUG_ASSERT(field_types == 0 ||
              field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
  field_pos++;
#endif
1241 1242 1243
  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);
unknown's avatar
unknown committed
1244 1245
  return store(str.ptr(), str.length(), str.charset());
}
1246

unknown's avatar
unknown committed
1247
bool Protocol_binary::store(float from, uint32 decimals, String *buffer)
1248 1249
{
  field_pos++;
1250
  char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
1251 1252 1253 1254 1255 1256 1257
  if (!to)
    return 1;
  float4store(to, from);
  return 0;
}


unknown's avatar
unknown committed
1258
bool Protocol_binary::store(double from, uint32 decimals, String *buffer)
1259 1260
{
  field_pos++;
1261
  char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
1262 1263 1264 1265 1266 1267 1268
  if (!to)
    return 1;
  float8store(to, from);
  return 0;
}


unknown's avatar
unknown committed
1269
bool Protocol_binary::store(Field *field)
1270 1271
{
  /*
1272
    We should not increment field_pos here as send_binary() will call another
1273 1274 1275 1276 1277 1278 1279 1280
    protocol function to do this for us
  */
  if (field->is_null())
    return store_null();
  return field->send_binary(this);
}


1281
bool Protocol_binary::store(MYSQL_TIME *tm)
1282 1283 1284 1285 1286
{
  char buff[12],*pos;
  uint length;
  field_pos++;
  pos= buff+1;
unknown's avatar
unknown committed
1287

1288
  int2store(pos, tm->year);
1289 1290 1291 1292 1293
  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;
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
  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
1304
  return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
1305 1306
}

1307
bool Protocol_binary::store_date(MYSQL_TIME *tm)
1308 1309 1310
{
  tm->hour= tm->minute= tm->second=0;
  tm->second_part= 0;
unknown's avatar
unknown committed
1311
  return Protocol_binary::store(tm);
1312 1313 1314
}


1315
bool Protocol_binary::store_time(MYSQL_TIME *tm)
1316
{
1317
  char buff[13], *pos;
1318 1319 1320 1321
  uint length;
  field_pos++;
  pos= buff+1;
  pos[0]= tm->neg ? 1 : 0;
1322 1323 1324 1325 1326 1327 1328
  if (tm->hour >= 24)
  {
    /* Fix if we come from Item::send */
    uint days= tm->hour/24;
    tm->hour-= days*24;
    tm->day+= days;
  }
unknown's avatar
unknown committed
1329
  int4store(pos+1, tm->day);
1330 1331 1332 1333
  pos[5]= (uchar) tm->hour;
  pos[6]= (uchar) tm->minute;
  pos[7]= (uchar) tm->second;
  int4store(pos+8, tm->second_part);
1334
  if (tm->second_part)
1335
    length=12;
1336
  else if (tm->hour || tm->minute || tm->second || tm->day)
1337
    length=8;
1338 1339 1340
  else
    length=0;
  buff[0]=(char) length;			// Length is stored first
1341
  return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
1342
}