mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			1200 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1200 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* Copyright (C) 2000-2003 MySQL AB
 | 
						|
 | 
						|
   This program is free software; you can redistribute it and/or modify
 | 
						|
   it under the terms of the GNU General Public License as published by
 | 
						|
   the Free Software Foundation; either version 2 of the License, or
 | 
						|
   (at your option) any later version.
 | 
						|
 | 
						|
   This program is distributed in the hope that it will be useful,
 | 
						|
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
   GNU General Public License for more details.
 | 
						|
 | 
						|
   You should have received a copy of the GNU General Public License
 | 
						|
   along with this program; if not, write to the Free Software
 | 
						|
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
						|
 | 
						|
/*
 | 
						|
  Low level functions for storing data to be send to the MySQL client
 | 
						|
  The actual communction is handled by the net_xxx functions in net_serv.cc
 | 
						|
*/
 | 
						|
 | 
						|
#ifdef USE_PRAGMA_IMPLEMENTATION
 | 
						|
#pragma implementation				// gcc: Class implementation
 | 
						|
#endif
 | 
						|
 | 
						|
#include "mysql_priv.h"
 | 
						|
#include <stdarg.h>
 | 
						|
 | 
						|
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
 | 
						|
 | 
						|
#ifndef EMBEDDED_LIBRARY
 | 
						|
bool Protocol::net_store_data(const char *from, uint length)
 | 
						|
#else
 | 
						|
bool Protocol_prep::net_store_data(const char *from, uint length)
 | 
						|
#endif
 | 
						|
{
 | 
						|
  ulong packet_length=packet->length();
 | 
						|
  /* 
 | 
						|
     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))
 | 
						|
    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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
	/* Send a error string to client */
 | 
						|
 | 
						|
void send_error(THD *thd, uint sql_errno, const char *err)
 | 
						|
{
 | 
						|
#ifndef EMBEDDED_LIBRARY 
 | 
						|
  uint length;
 | 
						|
  char buff[MYSQL_ERRMSG_SIZE+2], *pos;
 | 
						|
#endif
 | 
						|
  const char *orig_err= err;
 | 
						|
  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"));
 | 
						|
 | 
						|
#ifndef EMBEDDED_LIBRARY  /* TODO query cache in embedded library*/
 | 
						|
  query_cache_abort(net);
 | 
						|
#endif
 | 
						|
  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 */
 | 
						|
      }
 | 
						|
    }
 | 
						|
    orig_err= err;
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef EMBEDDED_LIBRARY
 | 
						|
  net->last_errno= sql_errno;
 | 
						|
  strmake(net->last_error, err, sizeof(net->last_error)-1);
 | 
						|
  strmov(net->sqlstate, mysql_errno_to_sqlstate(sql_errno));
 | 
						|
#else
 | 
						|
 | 
						|
  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);
 | 
						|
    pos= buff+2;
 | 
						|
    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
 | 
						|
    {
 | 
						|
      /* The first # is to make the protocol backward compatible */
 | 
						|
      buff[2]= '#';
 | 
						|
      pos= strmov(buff+3, mysql_errno_to_sqlstate(sql_errno));
 | 
						|
    }
 | 
						|
    length= (uint) (strmake(pos, err, MYSQL_ERRMSG_SIZE-1) - buff);
 | 
						|
    err=buff;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    length=(uint) strlen(err);
 | 
						|
    set_if_smaller(length,MYSQL_ERRMSG_SIZE-1);
 | 
						|
  }
 | 
						|
  VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length));
 | 
						|
#endif  /* EMBEDDED_LIBRARY*/
 | 
						|
  if (!thd->killed)
 | 
						|
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, sql_errno,
 | 
						|
                 orig_err ? orig_err : ER(sql_errno));
 | 
						|
  thd->is_fatal_error=0;			// Error message is given
 | 
						|
  thd->net.report_error= 0;
 | 
						|
 | 
						|
  /* Abort multi-result sets */
 | 
						|
  thd->lex->found_colon= 0;
 | 
						|
  thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Send a warning to the end user
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    send_warning()
 | 
						|
    thd			Thread handler
 | 
						|
    sql_errno		Warning number (error message)
 | 
						|
    err			Error string.  If not set, use ER(sql_errno)
 | 
						|
 | 
						|
  DESCRIPTION
 | 
						|
    Register the warning so that the user can get it with mysql_warnings()
 | 
						|
    Send an ok (+ warning count) to the end user.
 | 
						|
*/
 | 
						|
 | 
						|
void send_warning(THD *thd, uint sql_errno, const char *err)
 | 
						|
{
 | 
						|
  DBUG_ENTER("send_warning");  
 | 
						|
  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno,
 | 
						|
	       err ? err : ER(sql_errno));
 | 
						|
  send_ok(thd);
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
   Write error package and flush to client
 | 
						|
   It's a little too low level, but I don't want to use another buffer for
 | 
						|
   this
 | 
						|
*/
 | 
						|
 | 
						|
void
 | 
						|
net_printf(THD *thd, uint errcode, ...)
 | 
						|
{
 | 
						|
  va_list args;
 | 
						|
  uint length,offset;
 | 
						|
  const char *format;
 | 
						|
#ifndef EMBEDDED_LIBRARY
 | 
						|
  const char *text_pos;
 | 
						|
  int head_length= NET_HEADER_SIZE;
 | 
						|
#else
 | 
						|
  char text_pos[1024];
 | 
						|
#endif
 | 
						|
  NET *net= &thd->net;
 | 
						|
 | 
						|
  DBUG_ENTER("net_printf");
 | 
						|
  DBUG_PRINT("enter",("message: %u",errcode));
 | 
						|
 | 
						|
  thd->query_error=  1; // needed to catch query errors during replication
 | 
						|
#ifndef EMBEDDED_LIBRARY
 | 
						|
  query_cache_abort(net);	// Safety
 | 
						|
#endif
 | 
						|
  va_start(args,errcode);
 | 
						|
  /*
 | 
						|
    The following is needed to make net_printf() work with 0 argument for
 | 
						|
    errorcode and use the argument after that as the format string. This
 | 
						|
    is useful for rare errors that are not worth the hassle to put in
 | 
						|
    errmsg.sys, but at the same time, the message is not fixed text
 | 
						|
  */
 | 
						|
  if (errcode)
 | 
						|
    format= ER(errcode);
 | 
						|
  else
 | 
						|
  {
 | 
						|
    format=va_arg(args,char*);
 | 
						|
    errcode= ER_UNKNOWN_ERROR;
 | 
						|
  }
 | 
						|
  offset= (net->return_errno ?
 | 
						|
	   ((thd->client_capabilities & CLIENT_PROTOCOL_41) ?
 | 
						|
	    2+SQLSTATE_LENGTH+1 : 2) : 0);
 | 
						|
#ifndef EMBEDDED_LIBRARY
 | 
						|
  text_pos=(char*) net->buff + head_length + offset + 1;
 | 
						|
  length= (uint) ((char*)net->buff_end - text_pos);
 | 
						|
#else
 | 
						|
  length=sizeof(text_pos)-1;
 | 
						|
#endif
 | 
						|
  length=my_vsnprintf(my_const_cast(char*) (text_pos),
 | 
						|
                      min(length, sizeof(net->last_error)),
 | 
						|
                      format,args);
 | 
						|
  va_end(args);
 | 
						|
 | 
						|
  /* 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);
 | 
						|
 | 
						|
#ifndef EMBEDDED_LIBRARY
 | 
						|
  if (net->vio == 0)
 | 
						|
  {
 | 
						|
    if (thd->bootstrap)
 | 
						|
    {
 | 
						|
      /*
 | 
						|
	In bootstrap it's ok to print on stderr
 | 
						|
	This may also happen when we get an error from a slave thread
 | 
						|
      */
 | 
						|
      fprintf(stderr,"ERROR: %d  %s\n",errcode,text_pos);
 | 
						|
      thd->fatal_error();
 | 
						|
    }
 | 
						|
    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)
 | 
						|
  {
 | 
						|
    uchar *pos= net->buff+head_length+1;
 | 
						|
    int2store(pos, errcode);
 | 
						|
    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
 | 
						|
    {
 | 
						|
      pos[2]= '#';      /* To make the protocol backward compatible */
 | 
						|
      memcpy(pos+3, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset));
 | 
						|
#else
 | 
						|
  net->last_errno= errcode;
 | 
						|
  strmake(net->last_error, text_pos, length);
 | 
						|
  strmake(net->sqlstate, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH);
 | 
						|
#endif
 | 
						|
  if (!thd->killed)
 | 
						|
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, errcode,
 | 
						|
                 text_pos ? text_pos : ER(errcode));
 | 
						|
  thd->is_fatal_error=0;			// Error message is given
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Return ok to the client.
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    send_ok()
 | 
						|
    thd			Thread handler
 | 
						|
    affected_rows	Number of rows changed by statement
 | 
						|
    id			Auto_increment id for first row (if used)
 | 
						|
    message		Message to send to the client (Used by mysql_status)
 | 
						|
 | 
						|
  DESCRIPTION
 | 
						|
    The ok packet has the following structure
 | 
						|
 | 
						|
    0			Marker (1 byte)
 | 
						|
    affected_rows	Stored in 1-9 bytes
 | 
						|
    id			Stored in 1-9 bytes
 | 
						|
    server_status	Copy of thd->server_status;  Can be used by client
 | 
						|
			to check if we are inside an transaction
 | 
						|
			New in 4.0 protocol
 | 
						|
    warning_count	Stored in 2 bytes; New in 4.1 protocol
 | 
						|
    message		Stored as packed length (1-9 bytes) + message
 | 
						|
			Is not stored if no message
 | 
						|
 | 
						|
   If net->no_send_ok return without sending packet
 | 
						|
*/    
 | 
						|
 | 
						|
#ifndef EMBEDDED_LIBRARY
 | 
						|
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");
 | 
						|
 | 
						|
  if (net->no_send_ok || !net->vio)	// hack for re-parsing queries
 | 
						|
    DBUG_VOID_RETURN;
 | 
						|
 | 
						|
  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)
 | 
						|
  {
 | 
						|
    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));
 | 
						|
    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));
 | 
						|
  /* We can't anymore send an error to the client */
 | 
						|
  thd->net.report_error= 0;
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 | 
						|
 | 
						|
static char eof_buff[1]= { (char) 254 };        /* Marker for end of fields */
 | 
						|
 | 
						|
/*
 | 
						|
  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");
 | 
						|
  if (net->vio != 0)
 | 
						|
  {
 | 
						|
    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
 | 
						|
    {
 | 
						|
      uchar buff[5];
 | 
						|
      uint tmp= min(thd->total_warn_count, 65535);
 | 
						|
      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)
 | 
						|
	thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
 | 
						|
      int2store(buff+3, thd->server_status);
 | 
						|
      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;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
    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;
 | 
						|
  return my_net_write(net, eof_buff, 1) || net_flush(net);
 | 
						|
}
 | 
						|
 | 
						|
#endif /* EMBEDDED_LIBRARY */
 | 
						|
 | 
						|
/*
 | 
						|
  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.
 | 
						|
*/
 | 
						|
 | 
						|
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;
 | 
						|
  convert= &thd->convert_buffer;
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  field_types= 0;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol::flush()
 | 
						|
{
 | 
						|
#ifndef EMBEDDED_LIBRARY
 | 
						|
  return net_flush(&thd->net);
 | 
						|
#else
 | 
						|
  return 0;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Send name and type of result to client.
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    send_fields()
 | 
						|
    THD		Thread data object
 | 
						|
    list	List of items to send to client
 | 
						|
    flag	Bit mask with the following functions:
 | 
						|
		1 send number of rows
 | 
						|
		2 send default values
 | 
						|
 | 
						|
  DESCRIPTION
 | 
						|
    Sum fields has table name empty and field_name.
 | 
						|
 | 
						|
  RETURN VALUES
 | 
						|
    0	ok
 | 
						|
    1	Error  (Note that in this case the error is not sent to the client)
 | 
						|
*/
 | 
						|
 | 
						|
#ifndef EMBEDDED_LIBRARY
 | 
						|
bool Protocol::send_fields(List<Item> *list, uint flag)
 | 
						|
{
 | 
						|
  List_iterator_fast<Item> it(*list);
 | 
						|
  Item *item;
 | 
						|
  char buff[80];
 | 
						|
  String tmp((char*) buff,sizeof(buff),&my_charset_bin);
 | 
						|
  Protocol_simple prot(thd);
 | 
						|
  String *local_packet= prot.storage_packet();
 | 
						|
  CHARSET_INFO *thd_charset= thd->variables.character_set_results;
 | 
						|
  DBUG_ENTER("send_fields");
 | 
						|
 | 
						|
  if (flag & 1)
 | 
						|
  {				// Packet with number of elements
 | 
						|
    char *pos=net_store_length(buff, (uint) list->elements);
 | 
						|
    (void) my_net_write(&thd->net, buff,(uint) (pos-buff));
 | 
						|
  }
 | 
						|
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  field_types= (enum_field_types*) thd->alloc(sizeof(field_types) *
 | 
						|
					      list->elements);
 | 
						|
  uint count= 0;
 | 
						|
#endif
 | 
						|
 | 
						|
  while ((item=it++))
 | 
						|
  {
 | 
						|
    char *pos;
 | 
						|
    CHARSET_INFO *cs= system_charset_info;
 | 
						|
    Send_field field;
 | 
						|
    item->make_field(&field);
 | 
						|
    prot.prepare_for_resend();
 | 
						|
 | 
						|
    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
 | 
						|
    {
 | 
						|
      if (prot.store("def", 3, cs, thd_charset) ||
 | 
						|
	  prot.store(field.db_name, (uint) strlen(field.db_name),
 | 
						|
		     cs, thd_charset) ||
 | 
						|
	  prot.store(field.table_name, (uint) strlen(field.table_name),
 | 
						|
		     cs, thd_charset) ||
 | 
						|
	  prot.store(field.org_table_name, (uint) strlen(field.org_table_name),
 | 
						|
		     cs, thd_charset) ||
 | 
						|
	  prot.store(field.col_name, (uint) strlen(field.col_name),
 | 
						|
		     cs, thd_charset) ||
 | 
						|
	  prot.store(field.org_col_name, (uint) strlen(field.org_col_name),
 | 
						|
		     cs, thd_charset) ||
 | 
						|
	  local_packet->realloc(local_packet->length()+12))
 | 
						|
	goto err;
 | 
						|
      /* Store fixed length fields */
 | 
						|
      pos= (char*) local_packet->ptr()+local_packet->length();
 | 
						|
      *pos++= 12;				// Length of packed fields
 | 
						|
      if (item->collation.collation == &my_charset_bin || thd_charset == NULL)
 | 
						|
      {
 | 
						|
        /* No conversion */
 | 
						|
        int2store(pos, field.charsetnr);
 | 
						|
        int4store(pos+2, field.length);
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        /* With conversion */
 | 
						|
        int2store(pos, thd_charset->number);
 | 
						|
        uint char_len= field.length / item->collation.collation->mbmaxlen;
 | 
						|
        int4store(pos+2, char_len * thd_charset->mbmaxlen);
 | 
						|
      }
 | 
						|
      pos[6]= field.type;
 | 
						|
      int2store(pos+7,field.flags);
 | 
						|
      pos[9]= (char) field.decimals;
 | 
						|
      pos[10]= 0;				// For the future
 | 
						|
      pos[11]= 0;				// For the future
 | 
						|
      pos+= 12;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if (prot.store(field.table_name, (uint) strlen(field.table_name),
 | 
						|
		     cs, thd_charset) ||
 | 
						|
	  prot.store(field.col_name, (uint) strlen(field.col_name),
 | 
						|
		     cs, thd_charset) ||
 | 
						|
	  local_packet->realloc(local_packet->length()+10))
 | 
						|
	goto err;
 | 
						|
      pos= (char*) local_packet->ptr()+local_packet->length();
 | 
						|
 | 
						|
#ifdef TO_BE_DELETED_IN_6
 | 
						|
      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
 | 
						|
#endif
 | 
						|
      {
 | 
						|
	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;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    local_packet->length((uint) (pos - local_packet->ptr()));
 | 
						|
    if (flag & 2)
 | 
						|
      item->send(&prot, &tmp);			// Send default value
 | 
						|
    if (prot.write())
 | 
						|
      break;					/* purecov: inspected */
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
    field_types[count++]= field.type;
 | 
						|
#endif
 | 
						|
  }
 | 
						|
 | 
						|
  my_net_write(&thd->net, eof_buff, 1);
 | 
						|
  DBUG_RETURN(prepare_for_send(list));
 | 
						|
 | 
						|
err:
 | 
						|
  send_error(thd,ER_OUT_OF_RESOURCES);		/* purecov: inspected */
 | 
						|
  DBUG_RETURN(1);				/* purecov: inspected */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol::write()
 | 
						|
{
 | 
						|
  DBUG_ENTER("Protocol::write");
 | 
						|
  DBUG_RETURN(my_net_write(&thd->net, packet->ptr(), packet->length()));
 | 
						|
}
 | 
						|
#endif /* EMBEDDED_LIBRARY */
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Send \0 end terminated string
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    store()
 | 
						|
    from	NullS or \0 terminated string
 | 
						|
 | 
						|
  NOTES
 | 
						|
    In most cases one should use store(from, length) instead of this function
 | 
						|
 | 
						|
  RETURN VALUES
 | 
						|
    0		ok
 | 
						|
    1		error
 | 
						|
*/
 | 
						|
 | 
						|
bool Protocol::store(const char *from, CHARSET_INFO *cs)
 | 
						|
{
 | 
						|
  if (!from)
 | 
						|
    return store_null();
 | 
						|
  uint length= strlen(from);
 | 
						|
  return store(from, length, cs);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Send a set of strings as one long string with ',' in between
 | 
						|
*/
 | 
						|
 | 
						|
bool Protocol::store(I_List<i_string>* str_list)
 | 
						|
{
 | 
						|
  char buf[256];
 | 
						|
  String tmp(buf, sizeof(buf), &my_charset_bin);
 | 
						|
  uint32 len;
 | 
						|
  I_List_iterator<i_string> it(*str_list);
 | 
						|
  i_string* s;
 | 
						|
 | 
						|
  tmp.length(0);
 | 
						|
  while ((s=it++))
 | 
						|
  {
 | 
						|
    tmp.append(s->ptr);
 | 
						|
    tmp.append(',');
 | 
						|
  }
 | 
						|
  if ((len= tmp.length()))
 | 
						|
    len--;					// Remove last ','
 | 
						|
  return store((char*) tmp.ptr(), len,  tmp.charset());
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/****************************************************************************
 | 
						|
  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'
 | 
						|
****************************************************************************/
 | 
						|
 | 
						|
#ifndef EMBEDDED_LIBRARY
 | 
						|
void Protocol_simple::prepare_for_resend()
 | 
						|
{
 | 
						|
  packet->length(0);
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  field_pos= 0;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
bool Protocol_simple::store_null()
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  field_pos++;
 | 
						|
#endif
 | 
						|
  char buff[1];
 | 
						|
  buff[0]= (char)251;
 | 
						|
  return packet->append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  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)
 | 
						|
  {
 | 
						|
    uint dummy_errors;
 | 
						|
    return convert->copy(from, length, fromcs, tocs, &dummy_errors) ||
 | 
						|
           net_store_data(convert->ptr(), convert->length());
 | 
						|
  }
 | 
						|
  return net_store_data(from, length);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_simple::store(const char *from, uint length,
 | 
						|
			    CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
 | 
						|
{
 | 
						|
#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
 | 
						|
  return store_string_aux(from, length, fromcs, tocs);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_simple::store(const char *from, uint length,
 | 
						|
			    CHARSET_INFO *fromcs)
 | 
						|
{
 | 
						|
  CHARSET_INFO *tocs= this->thd->variables.character_set_results;
 | 
						|
#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
 | 
						|
  return store_string_aux(from, length, fromcs, tocs);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_simple::store_tiny(longlong from)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TINY);
 | 
						|
  field_pos++;
 | 
						|
#endif
 | 
						|
  char buff[20];
 | 
						|
  return net_store_data((char*) buff,
 | 
						|
			(uint) (int10_to_str((int) from,buff, -10)-buff));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_simple::store_short(longlong from)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_SHORT);
 | 
						|
  field_pos++;
 | 
						|
#endif
 | 
						|
  char buff[20];
 | 
						|
  return net_store_data((char*) buff,
 | 
						|
			(uint) (int10_to_str((int) from,buff, -10)-buff));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_simple::store_long(longlong from)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
              field_types[field_pos] == MYSQL_TYPE_INT24 ||
 | 
						|
              field_types[field_pos] == MYSQL_TYPE_LONG);
 | 
						|
  field_pos++;
 | 
						|
#endif
 | 
						|
  char buff[20];
 | 
						|
  return net_store_data((char*) buff,
 | 
						|
			(uint) (int10_to_str((long int)from,buff, (from <0)?-10:10)-buff));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_LONGLONG);
 | 
						|
  field_pos++;
 | 
						|
#endif
 | 
						|
  char buff[22];
 | 
						|
  return net_store_data((char*) buff,
 | 
						|
			(uint) (longlong10_to_str(from,buff,
 | 
						|
						  unsigned_flag ? 10 : -10)-
 | 
						|
				buff));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_simple::store(float from, uint32 decimals, String *buffer)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_FLOAT);
 | 
						|
  field_pos++;
 | 
						|
#endif
 | 
						|
  buffer->set((double) from, decimals, thd->charset());
 | 
						|
  return net_store_data((char*) buffer->ptr(), buffer->length());
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_simple::store(double from, uint32 decimals, String *buffer)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_DOUBLE);
 | 
						|
  field_pos++;
 | 
						|
#endif
 | 
						|
  buffer->set(from, decimals, thd->charset());
 | 
						|
  return net_store_data((char*) buffer->ptr(), buffer->length());
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_simple::store(Field *field)
 | 
						|
{
 | 
						|
  if (field->is_null())
 | 
						|
    return store_null();
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  field_pos++;
 | 
						|
#endif
 | 
						|
  char buff[MAX_FIELD_WIDTH];
 | 
						|
  String str(buff,sizeof(buff), &my_charset_bin);
 | 
						|
  CHARSET_INFO *tocs= this->thd->variables.character_set_results;
 | 
						|
 | 
						|
  field->val_str(&str);
 | 
						|
  return store_string_aux(str.ptr(), str.length(), str.charset(), tocs);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
   TODO:
 | 
						|
        Second_part format ("%06") needs to change when 
 | 
						|
        we support 0-6 decimals for time.
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
bool Protocol_simple::store(TIME *tm)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_DATETIME ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_TIMESTAMP);
 | 
						|
  field_pos++;
 | 
						|
#endif
 | 
						|
  char buff[40];
 | 
						|
  uint length;
 | 
						|
  length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d",
 | 
						|
			   (int) tm->year,
 | 
						|
			   (int) tm->month,
 | 
						|
			   (int) tm->day,
 | 
						|
			   (int) tm->hour,
 | 
						|
			   (int) tm->minute,
 | 
						|
			   (int) tm->second));
 | 
						|
  if (tm->second_part)
 | 
						|
    length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part));
 | 
						|
  return net_store_data((char*) buff, length);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_simple::store_date(TIME *tm)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_DATE);
 | 
						|
  field_pos++;
 | 
						|
#endif
 | 
						|
  char buff[MAX_DATE_STRING_REP_LENGTH];
 | 
						|
  int length= my_date_to_str(tm, buff);
 | 
						|
  return net_store_data(buff, (uint) length);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
   TODO:
 | 
						|
        Second_part format ("%06") needs to change when 
 | 
						|
        we support 0-6 decimals for time.
 | 
						|
*/
 | 
						|
 | 
						|
bool Protocol_simple::store_time(TIME *tm)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_TIME);
 | 
						|
  field_pos++;
 | 
						|
#endif
 | 
						|
  char buff[40];
 | 
						|
  uint length;
 | 
						|
  uint day= (tm->year || tm->month) ? 0 : tm->day;
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/****************************************************************************
 | 
						|
  Functions to handle the binary protocol used with prepared statements
 | 
						|
 | 
						|
  Data format:
 | 
						|
 | 
						|
   [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
 | 
						|
****************************************************************************/
 | 
						|
 | 
						|
bool Protocol_prep::prepare_for_send(List<Item> *item_list)
 | 
						|
{
 | 
						|
  Protocol::prepare_for_send(item_list);
 | 
						|
  bit_fields= (field_count+9)/8;
 | 
						|
  if (packet->alloc(bit_fields+1))
 | 
						|
    return 1;
 | 
						|
  /* prepare_for_resend will be called after this one */
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void Protocol_prep::prepare_for_resend()
 | 
						|
{
 | 
						|
  packet->length(bit_fields+1);
 | 
						|
  bzero((char*) packet->ptr(), 1+bit_fields);
 | 
						|
  field_pos=0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_prep::store(const char *from, uint length, CHARSET_INFO *fromcs)
 | 
						|
{
 | 
						|
  CHARSET_INFO *tocs= thd->variables.character_set_results;
 | 
						|
#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));
 | 
						|
#endif
 | 
						|
  field_pos++;
 | 
						|
  return store_string_aux(from, length, fromcs, tocs);
 | 
						|
}
 | 
						|
 | 
						|
bool Protocol_prep::store(const char *from,uint length,
 | 
						|
			  CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
 | 
						|
{
 | 
						|
#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));
 | 
						|
#endif
 | 
						|
  field_pos++;
 | 
						|
  return store_string_aux(from, length, fromcs, tocs);
 | 
						|
}
 | 
						|
 | 
						|
bool Protocol_prep::store_null()
 | 
						|
{
 | 
						|
  uint offset= (field_pos+2)/8+1, bit= (1 << ((field_pos+2) & 7));
 | 
						|
  /* Room for this as it's allocated in prepare_for_send */
 | 
						|
  char *to= (char*) packet->ptr()+offset;
 | 
						|
  *to= (char) ((uchar) *to | (uchar) bit);
 | 
						|
  field_pos++;
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_prep::store_tiny(longlong from)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_TINY);
 | 
						|
#endif
 | 
						|
  char buff[1];
 | 
						|
  field_pos++;
 | 
						|
  buff[0]= (uchar) from;
 | 
						|
  return packet->append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_prep::store_short(longlong from)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
        field_types[field_pos] == MYSQL_TYPE_SHORT ||
 | 
						|
        field_types[field_pos] == MYSQL_TYPE_YEAR);
 | 
						|
#endif
 | 
						|
  field_pos++;
 | 
						|
  char *to= packet->prep_append(2, PACKET_BUFFER_EXTRA_ALLOC);
 | 
						|
  if (!to)
 | 
						|
    return 1;
 | 
						|
  int2store(to, (int) from);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_prep::store_long(longlong from)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_INT24 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_LONG);
 | 
						|
#endif
 | 
						|
  field_pos++;
 | 
						|
  char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
 | 
						|
  if (!to)
 | 
						|
    return 1;
 | 
						|
  int4store(to, from);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_LONGLONG);
 | 
						|
#endif
 | 
						|
  field_pos++;
 | 
						|
  char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
 | 
						|
  if (!to)
 | 
						|
    return 1;
 | 
						|
  int8store(to, from);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_FLOAT);
 | 
						|
#endif
 | 
						|
  field_pos++;
 | 
						|
  char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
 | 
						|
  if (!to)
 | 
						|
    return 1;
 | 
						|
  float4store(to, from);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_prep::store(double from, uint32 decimals, String *buffer)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_DOUBLE);
 | 
						|
#endif
 | 
						|
  field_pos++;
 | 
						|
  char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
 | 
						|
  if (!to)
 | 
						|
    return 1;
 | 
						|
  float8store(to, from);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_prep::store(Field *field)
 | 
						|
{
 | 
						|
  /*
 | 
						|
    We should not increment field_pos here as send_binary() will call another
 | 
						|
    protocol function to do this for us
 | 
						|
  */
 | 
						|
  if (field->is_null())
 | 
						|
    return store_null();
 | 
						|
  return field->send_binary(this);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_prep::store(TIME *tm)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_DATETIME ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_DATE ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_TIMESTAMP);
 | 
						|
#endif
 | 
						|
  char buff[12],*pos;
 | 
						|
  uint length;
 | 
						|
  field_pos++;
 | 
						|
  pos= buff+1;
 | 
						|
 | 
						|
  int2store(pos, tm->year);
 | 
						|
  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;
 | 
						|
  int4store(pos+7, tm->second_part);
 | 
						|
  if (tm->second_part)
 | 
						|
    length=11;
 | 
						|
  else if (tm->hour || tm->minute || tm->second)
 | 
						|
    length=7;
 | 
						|
  else if (tm->year || tm->month || tm->day)
 | 
						|
    length=4;
 | 
						|
  else
 | 
						|
    length=0;
 | 
						|
  buff[0]=(char) length;			// Length is stored first
 | 
						|
  return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
 | 
						|
}
 | 
						|
 | 
						|
bool Protocol_prep::store_date(TIME *tm)
 | 
						|
{
 | 
						|
  tm->hour= tm->minute= tm->second=0;
 | 
						|
  tm->second_part= 0;
 | 
						|
  return Protocol_prep::store(tm);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Protocol_prep::store_time(TIME *tm)
 | 
						|
{
 | 
						|
#ifndef DEBUG_OFF
 | 
						|
  DBUG_ASSERT(field_types == 0 ||
 | 
						|
	      field_types[field_pos] == MYSQL_TYPE_TIME);
 | 
						|
#endif
 | 
						|
  char buff[13], *pos;
 | 
						|
  uint length;
 | 
						|
  field_pos++;
 | 
						|
  pos= buff+1;
 | 
						|
  pos[0]= tm->neg ? 1 : 0;
 | 
						|
  if (tm->hour >= 24)
 | 
						|
  {
 | 
						|
    /* Fix if we come from Item::send */
 | 
						|
    uint days= tm->hour/24;
 | 
						|
    tm->hour-= days*24;
 | 
						|
    tm->day+= days;
 | 
						|
  }
 | 
						|
  int4store(pos+1, tm->day);
 | 
						|
  pos[5]= (uchar) tm->hour;
 | 
						|
  pos[6]= (uchar) tm->minute;
 | 
						|
  pos[7]= (uchar) tm->second;
 | 
						|
  int4store(pos+8, tm->second_part);
 | 
						|
  if (tm->second_part)
 | 
						|
    length=12;
 | 
						|
  else if (tm->hour || tm->minute || tm->second || tm->day)
 | 
						|
    length=8;
 | 
						|
  else
 | 
						|
    length=0;
 | 
						|
  buff[0]=(char) length;			// Length is stored first
 | 
						|
  return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef EMBEDDED_LIBRARY
 | 
						|
/* Should be removed when we define the Protocol_cursor's future */
 | 
						|
bool Protocol_cursor::write()
 | 
						|
{
 | 
						|
  return Protocol_simple::write();
 | 
						|
}
 | 
						|
#endif
 | 
						|
 |