~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/protocol.cc

  • Committer: Brian Aker
  • Date: 2009-01-24 09:43:35 UTC
  • Revision ID: brian@gir-3.local-20090124094335-6qdtvc35gl5fvivz
Adding in an example singe thread scheduler

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2008 Sun Microsystems
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; version 2 of the License.
9
 
 *
10
 
 * This program is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 * GNU General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU General Public License
16
 
 * along with this program; if not, write to the Free Software
17
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
 */
19
 
 
20
 
#include "config.h"
21
 
#include <drizzled/gettext.h>
 
1
/* Copyright (C) 2000-2003 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
/**
 
17
  @file
 
18
 
 
19
  Low level functions for storing data to be send to the MySQL client.
 
20
  The actual communction is handled by the net_xxx functions in net_serv.cc
 
21
*/
 
22
#include <drizzled/server_includes.h>
22
23
#include <drizzled/error.h>
23
 
#include <drizzled/query_id.h>
24
24
#include <drizzled/sql_state.h>
 
25
#include <libdrizzle/pack.h>
 
26
#include <drizzled/protocol.h>
25
27
#include <drizzled/session.h>
26
 
#include "drizzled/internal/my_sys.h"
27
 
#include "drizzled/internal/m_string.h"
28
 
#include <algorithm>
29
 
 
30
 
#include "pack.h"
31
 
#include "errmsg.h"
32
 
#include "drizzle_protocol.h"
33
 
#include "options.h"
34
 
 
35
 
#define PROTOCOL_VERSION 10
36
 
 
37
 
namespace drizzled
38
 
{
39
 
extern uint32_t global_thread_id;
40
 
}
41
 
 
42
 
using namespace drizzled;
43
 
using namespace std;
44
 
 
45
 
namespace drizzle_protocol
46
 
{
47
 
 
48
 
 
49
 
static const uint32_t DRIZZLE_TCP_PORT= 4427;
 
28
 
50
29
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
51
 
static uint32_t port;
52
 
static uint32_t connect_timeout;
53
 
static uint32_t read_timeout;
54
 
static uint32_t write_timeout;
55
 
static uint32_t retry_count;
56
 
static uint32_t buffer_length;
57
 
static char* bind_address;
58
 
 
59
 
const char* ListenDrizzleProtocol::getHost(void) const
60
 
{
61
 
  return bind_address;
62
 
}
63
 
 
64
 
in_port_t ListenDrizzleProtocol::getPort(void) const
65
 
{
66
 
  char *env;
67
 
 
68
 
  if (port == 0)
69
 
  {
70
 
    port= DRIZZLE_TCP_PORT;
71
 
 
72
 
    if ((env = getenv("DRIZZLE_TCP_PORT")))
73
 
      port= (uint32_t) atoi(env);
74
 
 
75
 
    assert(port != 0);
76
 
  }
77
 
 
78
 
  return (in_port_t) port;
79
 
}
80
 
 
81
 
plugin::Client *ListenDrizzleProtocol::getClient(int fd)
82
 
{
83
 
  int new_fd;
84
 
  new_fd= acceptTcp(fd);
85
 
  if (new_fd == -1)
86
 
    return NULL;
87
 
 
88
 
  return new (nothrow) ClientDrizzleProtocol(new_fd, using_mysql41_protocol);
89
 
}
90
 
 
91
 
ClientDrizzleProtocol::ClientDrizzleProtocol(int fd, bool using_mysql41_protocol_arg):
92
 
  using_mysql41_protocol(using_mysql41_protocol_arg)
93
 
{
94
 
  net.vio= 0;
95
 
 
96
 
  if (fd == -1)
97
 
    return;
98
 
 
99
 
  if (drizzleclient_net_init_sock(&net, fd, 0, buffer_length))
100
 
    throw bad_alloc();
101
 
 
102
 
  drizzleclient_net_set_read_timeout(&net, read_timeout);
103
 
  drizzleclient_net_set_write_timeout(&net, write_timeout);
104
 
  net.retry_count=retry_count;
105
 
}
106
 
 
107
 
ClientDrizzleProtocol::~ClientDrizzleProtocol()
108
 
{
109
 
  if (net.vio)
110
 
    drizzleclient_vio_close(net.vio);
111
 
}
112
 
 
113
 
int ClientDrizzleProtocol::getFileDescriptor(void)
114
 
{
115
 
  return drizzleclient_net_get_sd(&net);
116
 
}
117
 
 
118
 
bool ClientDrizzleProtocol::isConnected()
119
 
{
120
 
  return net.vio != 0;
121
 
}
122
 
 
123
 
bool ClientDrizzleProtocol::isReading(void)
124
 
{
125
 
  return net.reading_or_writing == 1;
126
 
}
127
 
 
128
 
bool ClientDrizzleProtocol::isWriting(void)
129
 
{
130
 
  return net.reading_or_writing == 2;
131
 
}
132
 
 
133
 
bool ClientDrizzleProtocol::flush()
134
 
{
135
 
  if (net.vio == NULL)
136
 
    return false;
137
 
  bool ret= drizzleclient_net_write(&net, (unsigned char*) packet.ptr(),
138
 
                           packet.length());
139
 
  packet.length(0);
140
 
  return ret;
141
 
}
142
 
 
143
 
void ClientDrizzleProtocol::close(void)
144
 
{
145
 
  if (net.vio)
146
 
  { 
147
 
    drizzleclient_net_close(&net);
148
 
    drizzleclient_net_end(&net);
149
 
  }
150
 
}
151
 
 
152
 
bool ClientDrizzleProtocol::authenticate()
153
 
{
154
 
  bool connection_is_valid;
155
 
 
156
 
  /* Use "connect_timeout" value during connection phase */
157
 
  drizzleclient_net_set_read_timeout(&net, connect_timeout);
158
 
  drizzleclient_net_set_write_timeout(&net, connect_timeout);
159
 
 
160
 
  connection_is_valid= checkConnection();
161
 
 
162
 
  if (connection_is_valid)
163
 
    sendOK();
164
 
  else
165
 
  {
166
 
    sendError(session->main_da.sql_errno(), session->main_da.message());
167
 
    return false;
168
 
  }
169
 
 
170
 
  /* Connect completed, set read/write timeouts back to default */
171
 
  drizzleclient_net_set_read_timeout(&net, read_timeout);
172
 
  drizzleclient_net_set_write_timeout(&net, write_timeout);
173
 
  return true;
174
 
}
175
 
 
176
 
bool ClientDrizzleProtocol::readCommand(char **l_packet, uint32_t *packet_length)
177
 
{
178
 
  /*
179
 
    This thread will do a blocking read from the client which
180
 
    will be interrupted when the next command is received from
181
 
    the client, the connection is closed or "net_wait_timeout"
182
 
    number of seconds has passed
183
 
  */
184
 
#ifdef NEVER
185
 
  /* We can do this much more efficiently with poll timeouts or watcher thread,
186
 
     disabling for now, which means net_wait_timeout == read_timeout. */
187
 
  drizzleclient_net_set_read_timeout(&net,
188
 
                                     session->variables.net_wait_timeout);
189
 
#endif
190
 
 
191
 
  net.pkt_nr=0;
192
 
 
193
 
  *packet_length= drizzleclient_net_read(&net);
194
 
  if (*packet_length == packet_error)
195
 
  {
196
 
    /* Check if we can continue without closing the connection */
197
 
 
198
 
    if(net.last_errno== CR_NET_PACKET_TOO_LARGE)
199
 
      my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
200
 
    if (session->main_da.status() == Diagnostics_area::DA_ERROR)
201
 
      sendError(session->main_da.sql_errno(), session->main_da.message());
202
 
    else
203
 
      sendOK();
204
 
 
205
 
    if (net.error != 3)
206
 
      return false;                       // We have to close it.
207
 
 
208
 
    net.error= 0;
209
 
    *packet_length= 0;
210
 
    return true;
211
 
  }
212
 
 
213
 
  *l_packet= (char*) net.read_pos;
214
 
 
215
 
  /*
216
 
    'packet_length' contains length of data, as it was stored in packet
217
 
    header. In case of malformed header, drizzleclient_net_read returns zero.
218
 
    If packet_length is not zero, drizzleclient_net_read ensures that the returned
219
 
    number of bytes was actually read from network.
220
 
    There is also an extra safety measure in drizzleclient_net_read:
221
 
    it sets packet[packet_length]= 0, but only for non-zero packets.
222
 
  */
223
 
 
224
 
  if (*packet_length == 0)                       /* safety */
225
 
  {
226
 
    /* Initialize with COM_SLEEP packet */
227
 
    (*l_packet)[0]= (unsigned char) COM_SLEEP;
228
 
    *packet_length= 1;
229
 
  }
230
 
  else if (using_mysql41_protocol)
231
 
  {
232
 
    /* Map from MySQL commands to Drizzle commands. */
233
 
    switch ((int)(*l_packet)[0])
234
 
    {
235
 
    case 0: /* SLEEP */
236
 
    case 1: /* QUIT */
237
 
    case 2: /* INIT_DB */
238
 
    case 3: /* QUERY */
239
 
      break;
240
 
 
241
 
    case 8: /* SHUTDOWN */
242
 
      (*l_packet)[0]= (unsigned char) COM_SHUTDOWN;
243
 
      break;
244
 
 
245
 
    case 14: /* PING */
246
 
      (*l_packet)[0]= (unsigned char) COM_SHUTDOWN;
247
 
      break;
248
 
 
249
 
 
250
 
    default:
251
 
      /* Just drop connection for MySQL commands we don't support. */
252
 
      (*l_packet)[0]= (unsigned char) COM_QUIT;
253
 
      *packet_length= 1;
254
 
      break;
255
 
    }
256
 
  }
257
 
 
258
 
  /* Do not rely on drizzleclient_net_read, extra safety against programming errors. */
259
 
  (*l_packet)[*packet_length]= '\0';                  /* safety */
260
 
 
261
 
#ifdef NEVER
262
 
  /* See comment above. */
263
 
  /* Restore read timeout value */
264
 
  drizzleclient_net_set_read_timeout(&net,
265
 
                                     session->variables.net_read_timeout);
266
 
#endif
267
 
 
268
 
  return true;
 
30
/* Declared non-static only because of the embedded library. */
 
31
static void net_send_error_packet(Session *session, uint32_t sql_errno, const char *err);
 
32
static void write_eof_packet(Session *session, NET *net,
 
33
                             uint32_t server_status, uint32_t total_warn_count);
 
34
 
 
35
bool Protocol::net_store_data(const unsigned char *from, size_t length)
 
36
{
 
37
  size_t packet_length= packet->length();
 
38
  /*
 
39
     The +9 comes from that strings of length longer than 16M require
 
40
     9 bytes to be stored (see net_store_length).
 
41
  */
 
42
  if (packet_length+9+length > packet->alloced_length() &&
 
43
      packet->realloc(packet_length+9+length))
 
44
    return 1;
 
45
  unsigned char *to= net_store_length((unsigned char*) packet->ptr()+packet_length, length);
 
46
  memcpy(to,from,length);
 
47
  packet->length((size_t) (to+length-(unsigned char*) packet->ptr()));
 
48
  return 0;
 
49
}
 
50
 
 
51
 
 
52
 
 
53
 
 
54
/*
 
55
  net_store_data() - extended version with character set conversion.
 
56
 
 
57
  It is optimized for short strings whose length after
 
58
  conversion is garanteed to be less than 251, which accupies
 
59
  exactly one byte to store length. It allows not to use
 
60
  the "convert" member as a temporary buffer, conversion
 
61
  is done directly to the "packet" member.
 
62
  The limit 251 is good enough to optimize send_fields()
 
63
  because column, table, database names fit into this limit.
 
64
*/
 
65
 
 
66
bool Protocol::net_store_data(const unsigned char *from, size_t length,
 
67
                              const CHARSET_INFO * const from_cs,
 
68
                                                          const CHARSET_INFO * const to_cs)
 
69
{
 
70
  uint32_t dummy_errors;
 
71
  /* Calculate maxumum possible result length */
 
72
  uint32_t conv_length= to_cs->mbmaxlen * length / from_cs->mbminlen;
 
73
  if (conv_length > 250)
 
74
  {
 
75
    /*
 
76
      For strings with conv_length greater than 250 bytes
 
77
      we don't know how many bytes we will need to store length: one or two,
 
78
      because we don't know result length until conversion is done.
 
79
      For example, when converting from utf8 (mbmaxlen=3) to latin1,
 
80
      conv_length=300 means that the result length can vary between 100 to 300.
 
81
      length=100 needs one byte, length=300 needs to bytes.
 
82
 
 
83
      Thus conversion directly to "packet" is not worthy.
 
84
      Let's use "convert" as a temporary buffer.
 
85
    */
 
86
    return (convert->copy((const char*) from, length, from_cs,
 
87
                          to_cs, &dummy_errors) ||
 
88
            net_store_data((const unsigned char*) convert->ptr(), convert->length()));
 
89
  }
 
90
 
 
91
  size_t packet_length= packet->length();
 
92
  size_t new_length= packet_length + conv_length + 1;
 
93
 
 
94
  if (new_length > packet->alloced_length() && packet->realloc(new_length))
 
95
    return 1;
 
96
 
 
97
  char *length_pos= (char*) packet->ptr() + packet_length;
 
98
  char *to= length_pos + 1;
 
99
 
 
100
  to+= copy_and_convert(to, conv_length, to_cs,
 
101
                        (const char*) from, length, from_cs, &dummy_errors);
 
102
 
 
103
  net_store_length((unsigned char*) length_pos, to - length_pos - 1);
 
104
  packet->length((uint) (to - packet->ptr()));
 
105
  return 0;
 
106
}
 
107
 
 
108
 
 
109
/**
 
110
  Send a error string to client.
 
111
 
 
112
  Design note:
 
113
  net_printf_error and net_send_error are low-level functions
 
114
  that shall be used only when a new connection is being
 
115
  established or at server startup.
 
116
 
 
117
  For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
 
118
  critical that every error that can be intercepted is issued in one
 
119
  place only, my_message_sql.
 
120
*/
 
121
void net_send_error(Session *session, uint32_t sql_errno, const char *err)
 
122
{
 
123
  assert(sql_errno);
 
124
  assert(err && err[0]);
 
125
 
 
126
  /*
 
127
    It's one case when we can push an error even though there
 
128
    is an OK or EOF already.
 
129
  */
 
130
  session->main_da.can_overwrite_status= true;
 
131
 
 
132
  /* Abort multi-result sets */
 
133
  session->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
 
134
 
 
135
  net_send_error_packet(session, sql_errno, err);
 
136
 
 
137
  session->main_da.can_overwrite_status= false;
269
138
}
270
139
 
271
140
/**
274
143
  The ok packet has the following structure:
275
144
 
276
145
  - 0               : Marker (1 byte)
277
 
  - affected_rows    : Stored in 1-9 bytes
278
 
  - id        : Stored in 1-9 bytes
279
 
  - server_status    : Copy of session->server_status;  Can be used by client
 
146
  - affected_rows       : Stored in 1-9 bytes
 
147
  - id          : Stored in 1-9 bytes
 
148
  - server_status       : Copy of session->server_status;  Can be used by client
280
149
  to check if we are inside an transaction.
281
 
  New in 4.0 client
282
 
  - warning_count    : Stored in 2 bytes; New in 4.1 client
283
 
  - message        : Stored as packed length (1-9 bytes) + message.
 
150
  New in 4.0 protocol
 
151
  - warning_count       : Stored in 2 bytes; New in 4.1 protocol
 
152
  - message             : Stored as packed length (1-9 bytes) + message.
284
153
  Is not stored if no message.
285
154
 
286
 
  @param session           Thread handler
287
 
  @param affected_rows       Number of rows changed by statement
288
 
  @param id           Auto_increment id for first row (if used)
289
 
  @param message       Message to send to the client (Used by mysql_status)
 
155
  @param session                   Thread handler
 
156
  @param affected_rows     Number of rows changed by statement
 
157
  @param id                Auto_increment id for first row (if used)
 
158
  @param message           Message to send to the client (Used by mysql_status)
290
159
*/
291
160
 
292
 
void ClientDrizzleProtocol::sendOK()
 
161
static void
 
162
net_send_ok(Session *session,
 
163
            uint32_t server_status, uint32_t total_warn_count,
 
164
            ha_rows affected_rows, uint64_t id, const char *message)
293
165
{
 
166
  NET *net= &session->net;
294
167
  unsigned char buff[DRIZZLE_ERRMSG_SIZE+10],*pos;
295
 
  const char *message= NULL;
296
 
  uint32_t tmp;
297
168
 
298
 
  if (!net.vio)    // hack for re-parsing queries
 
169
  if (! net->vio)       // hack for re-parsing queries
299
170
  {
300
171
    return;
301
172
  }
302
173
 
303
 
  buff[0]=0;                    // No fields
304
 
  if (session->main_da.status() == Diagnostics_area::DA_OK)
305
 
  {
306
 
    if (client_capabilities & CLIENT_FOUND_ROWS && session->main_da.found_rows())
307
 
      pos=drizzleclient_net_store_length(buff+1,session->main_da.found_rows());
308
 
    else
309
 
      pos=drizzleclient_net_store_length(buff+1,session->main_da.affected_rows());
310
 
    pos=drizzleclient_net_store_length(pos, session->main_da.last_insert_id());
311
 
    int2store(pos, session->main_da.server_status());
312
 
    pos+=2;
313
 
    tmp= min(session->main_da.total_warn_count(), (uint32_t)65535);
314
 
    message= session->main_da.message();
315
 
  }
316
 
  else
317
 
  {
318
 
    pos=drizzleclient_net_store_length(buff+1,0);
319
 
    pos=drizzleclient_net_store_length(pos, 0);
320
 
    int2store(pos, session->server_status);
321
 
    pos+=2;
322
 
    tmp= min(session->total_warn_count, (uint32_t)65535);
323
 
  }
 
174
  buff[0]=0;                                    // No fields
 
175
  pos=net_store_length(buff+1,affected_rows);
 
176
  pos=net_store_length(pos, id);
 
177
 
 
178
  int2store(pos, server_status);
 
179
  pos+=2;
324
180
 
325
181
  /* We can only return up to 65535 warnings in two bytes */
 
182
  uint32_t tmp= cmin(total_warn_count, (uint)65535);
326
183
  int2store(pos, tmp);
327
184
  pos+= 2;
328
185
 
329
186
  session->main_da.can_overwrite_status= true;
330
187
 
331
188
  if (message && message[0])
332
 
  {
333
 
    size_t length= strlen(message);
334
 
    pos=drizzleclient_net_store_length(pos,length);
335
 
    memcpy(pos,(unsigned char*) message,length);
336
 
    pos+=length;
337
 
  }
338
 
  drizzleclient_net_write(&net, buff, (size_t) (pos-buff));
339
 
  drizzleclient_net_flush(&net);
 
189
    pos= net_store_data(pos, (unsigned char*) message, strlen(message));
 
190
  my_net_write(net, buff, (size_t) (pos-buff));
 
191
  net_flush(net);
340
192
 
341
193
  session->main_da.can_overwrite_status= false;
342
194
}
346
198
 
347
199
  The eof packet has the following structure:
348
200
 
349
 
  - 254    (DRIZZLE_PROTOCOL_NO_MORE_DATA)    : Marker (1 byte)
350
 
  - warning_count    : Stored in 2 bytes; New in 4.1 client
351
 
  - status_flag    : Stored in 2 bytes;
 
201
  - 254 (DRIZZLE_PROTOCOL_NO_MORE_DATA) : Marker (1 byte)
 
202
  - warning_count       : Stored in 2 bytes; New in 4.1 protocol
 
203
  - status_flag : Stored in 2 bytes;
352
204
  For flags like SERVER_MORE_RESULTS_EXISTS.
353
205
 
354
206
  Note that the warning count will not be sent if 'no_flush' is set as
355
207
  we don't want to report the warning count until all data is sent to the
356
208
  client.
 
209
 
 
210
  @param session                Thread handler
 
211
  @param no_flush       Set to 1 if there will be more data to the client,
 
212
                    like in send_fields().
357
213
*/
358
214
 
359
 
void ClientDrizzleProtocol::sendEOF()
 
215
static void
 
216
net_send_eof(Session *session, uint32_t server_status, uint32_t total_warn_count)
360
217
{
 
218
  NET *net= &session->net;
361
219
  /* Set to true if no active vio, to work well in case of --init-file */
362
 
  if (net.vio != 0)
 
220
  if (net->vio != 0)
363
221
  {
364
222
    session->main_da.can_overwrite_status= true;
365
 
    writeEOFPacket(session->main_da.server_status(),
366
 
                   session->main_da.total_warn_count());
367
 
    drizzleclient_net_flush(&net);
 
223
    write_eof_packet(session, net, server_status, total_warn_count);
 
224
    net_flush(net);
368
225
    session->main_da.can_overwrite_status= false;
369
226
  }
370
 
  packet.shrink(buffer_length);
371
 
}
372
 
 
373
 
 
374
 
void ClientDrizzleProtocol::sendError(uint32_t sql_errno, const char *err)
375
 
{
 
227
}
 
228
 
 
229
 
 
230
/**
 
231
  Format EOF packet according to the current protocol and
 
232
  write it to the network output buffer.
 
233
*/
 
234
 
 
235
static void write_eof_packet(Session *session, NET *net,
 
236
                             uint32_t server_status,
 
237
                             uint32_t total_warn_count)
 
238
{
 
239
  unsigned char buff[5];
 
240
  /*
 
241
    Don't send warn count during SP execution, as the warn_list
 
242
    is cleared between substatements, and mysqltest gets confused
 
243
  */
 
244
  uint32_t tmp= cmin(total_warn_count, (uint)65535);
 
245
  buff[0]= DRIZZLE_PROTOCOL_NO_MORE_DATA;
 
246
  int2store(buff+1, tmp);
 
247
  /*
 
248
    The following test should never be true, but it's better to do it
 
249
    because if 'is_fatal_error' is set the server is not going to execute
 
250
    other queries (see the if test in dispatch_command / COM_QUERY)
 
251
  */
 
252
  if (session->is_fatal_error)
 
253
    server_status&= ~SERVER_MORE_RESULTS_EXISTS;
 
254
  int2store(buff + 3, server_status);
 
255
  my_net_write(net, buff, 5);
 
256
}
 
257
 
 
258
void net_send_error_packet(Session *session, uint32_t sql_errno, const char *err)
 
259
{
 
260
  NET *net= &session->net;
376
261
  uint32_t length;
377
262
  /*
378
263
    buff[]: sql_errno:2 + ('#':1 + SQLSTATE_LENGTH:5) + DRIZZLE_ERRMSG_SIZE:512
379
264
  */
380
265
  unsigned char buff[2+1+SQLSTATE_LENGTH+DRIZZLE_ERRMSG_SIZE], *pos;
381
266
 
382
 
  assert(sql_errno);
383
 
  assert(err && err[0]);
384
 
 
385
 
  /*
386
 
    It's one case when we can push an error even though there
387
 
    is an OK or EOF already.
388
 
  */
389
 
  session->main_da.can_overwrite_status= true;
390
 
 
391
 
  /* Abort multi-result sets */
392
 
  session->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
393
 
 
394
 
  /**
395
 
    Send a error string to client.
396
 
 
397
 
    For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
398
 
    critical that every error that can be intercepted is issued in one
399
 
    place only, my_message_sql.
400
 
  */
401
 
 
402
 
  if (net.vio == 0)
 
267
  if (net->vio == 0)
403
268
  {
404
269
    return;
405
270
  }
407
272
  int2store(buff,sql_errno);
408
273
  pos= buff+2;
409
274
 
410
 
  /* The first # is to make the client backward compatible */
 
275
  /* The first # is to make the protocol backward compatible */
411
276
  buff[2]= '#';
412
277
  pos= (unsigned char*) strcpy((char*) buff+3, drizzle_errno_to_sqlstate(sql_errno));
413
278
  pos+= strlen(drizzle_errno_to_sqlstate(sql_errno));
418
283
  length= (uint32_t)(tmp-(char*)buff);
419
284
  err= (char*) buff;
420
285
 
421
 
  drizzleclient_net_write_command(&net,(unsigned char) 255, (unsigned char*) "", 0, (unsigned char*) err, length);
422
 
 
423
 
  session->main_da.can_overwrite_status= false;
424
 
}
 
286
  net_write_command(net,(unsigned char) 255, (unsigned char*) "", 0, (unsigned char*) err, length);
 
287
  return;
 
288
}
 
289
 
 
290
 
 
291
/**
 
292
  Faster net_store_length when we know that length is less than 65536.
 
293
  We keep a separate version for that range because it's widely used in
 
294
  libmysql.
 
295
 
 
296
  uint32_t is used as agrument type because of MySQL type conventions:
 
297
  - uint32_t for 0..65536
 
298
  - ulong for 0..4294967296
 
299
  - uint64_t for bigger numbers.
 
300
*/
 
301
 
 
302
static unsigned char *net_store_length_fast(unsigned char *packet, uint32_t length)
 
303
{
 
304
  if (length < 251)
 
305
  {
 
306
    *packet=(unsigned char) length;
 
307
    return packet+1;
 
308
  }
 
309
  *packet++=252;
 
310
  int2store(packet,(uint32_t) length);
 
311
 
 
312
  return packet+2;
 
313
}
 
314
 
 
315
/**
 
316
  Send the status of the current statement execution over network.
 
317
 
 
318
  @param  session   in fact, carries two parameters, NET for the transport and
 
319
                Diagnostics_area as the source of status information.
 
320
 
 
321
  In MySQL, there are two types of SQL statements: those that return
 
322
  a result set and those that return status information only.
 
323
 
 
324
  If a statement returns a result set, it consists of 3 parts:
 
325
  - result set meta-data
 
326
  - variable number of result set rows (can be 0)
 
327
  - followed and terminated by EOF or ERROR packet
 
328
 
 
329
  Once the  client has seen the meta-data information, it always
 
330
  expects an EOF or ERROR to terminate the result set. If ERROR is
 
331
  received, the result set rows are normally discarded (this is up
 
332
  to the client implementation, libmysql at least does discard them).
 
333
  EOF, on the contrary, means "successfully evaluated the entire
 
334
  result set". Since we don't know how many rows belong to a result
 
335
  set until it's evaluated, EOF/ERROR is the indicator of the end
 
336
  of the row stream. Note, that we can not buffer result set rows
 
337
  on the server -- there may be an arbitrary number of rows. But
 
338
  we do buffer the last packet (EOF/ERROR) in the Diagnostics_area and
 
339
  delay sending it till the very end of execution (here), to be able to
 
340
  change EOF to an ERROR if commit failed or some other error occurred
 
341
  during the last cleanup steps taken after execution.
 
342
 
 
343
  A statement that does not return a result set doesn't send result
 
344
  set meta-data either. Instead it returns one of:
 
345
  - OK packet
 
346
  - ERROR packet.
 
347
  Similarly to the EOF/ERROR of the previous statement type, OK/ERROR
 
348
  packet is "buffered" in the diagnostics area and sent to the client
 
349
  in the end of statement.
 
350
 
 
351
  @pre  The diagnostics area is assigned or disabled. It can not be empty
 
352
        -- we assume that every SQL statement or COM_* command
 
353
        generates OK, ERROR, or EOF status.
 
354
 
 
355
  @post The status information is encoded to protocol format and sent to the
 
356
        client.
 
357
 
 
358
  @return We conventionally return void, since the only type of error
 
359
          that can happen here is a NET (transport) error, and that one
 
360
          will become visible when we attempt to read from the NET the
 
361
          next command.
 
362
          Diagnostics_area::is_sent is set for debugging purposes only.
 
363
*/
 
364
 
 
365
void net_end_statement(Session *session)
 
366
{
 
367
  assert(! session->main_da.is_sent);
 
368
 
 
369
  /* Can not be true, but do not take chances in production. */
 
370
  if (session->main_da.is_sent)
 
371
    return;
 
372
 
 
373
  switch (session->main_da.status()) {
 
374
  case Diagnostics_area::DA_ERROR:
 
375
    /* The query failed, send error to log and abort bootstrap. */
 
376
    net_send_error(session,
 
377
                   session->main_da.sql_errno(),
 
378
                   session->main_da.message());
 
379
    break;
 
380
  case Diagnostics_area::DA_EOF:
 
381
    net_send_eof(session,
 
382
                 session->main_da.server_status(),
 
383
                 session->main_da.total_warn_count());
 
384
    break;
 
385
  case Diagnostics_area::DA_OK:
 
386
    net_send_ok(session,
 
387
                session->main_da.server_status(),
 
388
                session->main_da.total_warn_count(),
 
389
                session->main_da.affected_rows(),
 
390
                session->main_da.last_insert_id(),
 
391
                session->main_da.message());
 
392
    break;
 
393
  case Diagnostics_area::DA_DISABLED:
 
394
    break;
 
395
  case Diagnostics_area::DA_EMPTY:
 
396
  default:
 
397
    //TODO: Something is being masked here by commenting this out
 
398
    //  assert(0);
 
399
    net_send_ok(session, session->server_status, session->total_warn_count,
 
400
                0, 0, NULL);
 
401
    break;
 
402
  }
 
403
  session->main_da.is_sent= true;
 
404
}
 
405
 
 
406
 
 
407
/****************************************************************************
 
408
  Functions used by the protocol functions (like net_send_ok) to store
 
409
  strings and numbers in the header result packet.
 
410
****************************************************************************/
 
411
 
 
412
/* The following will only be used for short strings < 65K */
 
413
 
 
414
unsigned char *net_store_data(unsigned char *to, const unsigned char *from, size_t length)
 
415
{
 
416
  to=net_store_length_fast(to,length);
 
417
  memcpy(to,from,length);
 
418
  return to+length;
 
419
}
 
420
 
 
421
unsigned char *net_store_data(unsigned char *to,int32_t from)
 
422
{
 
423
  char buff[20];
 
424
  uint32_t length=(uint) (int10_to_str(from,buff,10)-buff);
 
425
  to=net_store_length_fast(to,length);
 
426
  memcpy(to,buff,length);
 
427
  return to+length;
 
428
}
 
429
 
 
430
unsigned char *net_store_data(unsigned char *to,int64_t from)
 
431
{
 
432
  char buff[22];
 
433
  uint32_t length=(uint) (int64_t10_to_str(from,buff,10)-buff);
 
434
  to=net_store_length_fast(to,length);
 
435
  memcpy(to,buff,length);
 
436
  return to+length;
 
437
}
 
438
 
 
439
 
 
440
/*****************************************************************************
 
441
  Default Protocol functions
 
442
*****************************************************************************/
 
443
 
 
444
void Protocol::init(Session *session_arg)
 
445
{
 
446
  session=session_arg;
 
447
  packet= &session->packet;
 
448
  convert= &session->convert_buffer;
 
449
}
 
450
 
 
451
/**
 
452
  Finish the result set with EOF packet, as is expected by the client,
 
453
  if there is an error evaluating the next row and a continue handler
 
454
  for the error.
 
455
*/
 
456
 
 
457
void Protocol::end_partial_result_set(Session *session)
 
458
{
 
459
  net_send_eof(session, session->server_status, 0 /* no warnings, we're inside SP */);
 
460
}
 
461
 
 
462
 
 
463
bool Protocol::flush()
 
464
{
 
465
  return net_flush(&session->net);
 
466
}
 
467
 
425
468
 
426
469
/**
427
470
  Send name and type of result to client.
428
471
 
429
472
  Sum fields has table name empty and field_name.
430
473
 
431
 
  @param Session        Thread data object
432
 
  @param list            List of items to send to client
433
 
  @param flag            Bit mask with the following functions:
 
474
  @param Session                Thread data object
 
475
  @param list           List of items to send to client
 
476
  @param flag           Bit mask with the following functions:
434
477
                        - 1 send number of rows
435
478
                        - 2 send default values
436
479
                        - 4 don't write eof packet
437
480
 
438
481
  @retval
439
 
    0    ok
 
482
    0   ok
440
483
  @retval
441
 
    1    Error  (Note that in this case the error is not sent to the
 
484
    1   Error  (Note that in this case the error is not sent to the
442
485
    client)
443
486
*/
444
 
bool ClientDrizzleProtocol::sendFields(List<Item> *list)
 
487
bool Protocol::send_fields(List<Item> *list, uint32_t flags)
445
488
{
446
489
  List_iterator_fast<Item> it(*list);
447
490
  Item *item;
448
491
  unsigned char buff[80];
449
492
  String tmp((char*) buff,sizeof(buff),&my_charset_bin);
 
493
  Protocol_text prot(session);
 
494
  String *local_packet= prot.storage_packet();
 
495
  const CHARSET_INFO * const session_charset= default_charset_info;
450
496
 
451
 
  unsigned char *row_pos= drizzleclient_net_store_length(buff, list->elements);
452
 
  (void) drizzleclient_net_write(&net, buff, (size_t) (row_pos-buff));
 
497
  if (flags & SEND_NUM_ROWS)
 
498
  {                             // Packet with number of elements
 
499
    unsigned char *pos= net_store_length(buff, list->elements);
 
500
    (void) my_net_write(&session->net, buff, (size_t) (pos-buff));
 
501
  }
453
502
 
454
503
  while ((item=it++))
455
504
  {
456
505
    char *pos;
457
 
    SendField field;
 
506
    const CHARSET_INFO * const cs= system_charset_info;
 
507
    Send_field field;
458
508
    item->make_field(&field);
459
509
 
460
 
    packet.length(0);
461
 
 
462
 
    if (store(STRING_WITH_LEN("def")) ||
463
 
        store(field.db_name) ||
464
 
        store(field.table_name) ||
465
 
        store(field.org_table_name) ||
466
 
        store(field.col_name) ||
467
 
        store(field.org_col_name) ||
468
 
        packet.realloc(packet.length()+12))
 
510
    prot.prepare_for_resend();
 
511
 
 
512
 
 
513
    if (prot.store(STRING_WITH_LEN("def"), cs, session_charset) ||
 
514
        prot.store(field.db_name, (uint) strlen(field.db_name),
 
515
                   cs, session_charset) ||
 
516
        prot.store(field.table_name, (uint) strlen(field.table_name),
 
517
                   cs, session_charset) ||
 
518
        prot.store(field.org_table_name, (uint) strlen(field.org_table_name),
 
519
                   cs, session_charset) ||
 
520
        prot.store(field.col_name, (uint) strlen(field.col_name),
 
521
                   cs, session_charset) ||
 
522
        prot.store(field.org_col_name, (uint) strlen(field.org_col_name),
 
523
                   cs, session_charset) ||
 
524
        local_packet->realloc(local_packet->length()+12))
469
525
      goto err;
470
526
 
471
527
    /* Store fixed length fields */
472
 
    pos= (char*) packet.ptr()+packet.length();
473
 
    *pos++= 12;                // Length of packed fields
474
 
    /* No conversion */
475
 
    int2store(pos, field.charsetnr);
476
 
    int4store(pos+2, field.length);
477
 
 
478
 
    if (using_mysql41_protocol)
 
528
    pos= (char*) local_packet->ptr()+local_packet->length();
 
529
    *pos++= 12;                         // Length of packed fields
 
530
    if (item->collation.collation == &my_charset_bin || session_charset == NULL)
479
531
    {
480
 
      /* Switch to MySQL field numbering. */
481
 
      switch (field.type)
482
 
      {
483
 
      case DRIZZLE_TYPE_LONG:
484
 
        pos[6]= 3;
485
 
        break;
486
 
 
487
 
      case DRIZZLE_TYPE_DOUBLE:
488
 
        pos[6]= 5;
489
 
        break;
490
 
 
491
 
      case DRIZZLE_TYPE_NULL:
492
 
        pos[6]= 6;
493
 
        break;
494
 
 
495
 
      case DRIZZLE_TYPE_TIMESTAMP:
496
 
        pos[6]= 7;
497
 
        break;
498
 
 
499
 
      case DRIZZLE_TYPE_LONGLONG:
500
 
        pos[6]= 8;
501
 
        break;
502
 
 
503
 
      case DRIZZLE_TYPE_DATETIME:
504
 
        pos[6]= 12;
505
 
        break;
506
 
 
507
 
      case DRIZZLE_TYPE_DATE:
508
 
        pos[6]= 14;
509
 
        break;
510
 
 
511
 
      case DRIZZLE_TYPE_VARCHAR:
512
 
        pos[6]= 15;
513
 
        break;
514
 
 
515
 
      case DRIZZLE_TYPE_DECIMAL:
516
 
        pos[6]= (char)246;
517
 
        break;
518
 
 
519
 
      case DRIZZLE_TYPE_ENUM:
520
 
        pos[6]= (char)247;
521
 
        break;
522
 
 
523
 
      case DRIZZLE_TYPE_BLOB:
524
 
        pos[6]= (char)252;
525
 
        break;
526
 
      }
 
532
      /* No conversion */
 
533
      int2store(pos, field.charsetnr);
 
534
      int4store(pos+2, field.length);
527
535
    }
528
536
    else
529
537
    {
530
 
      /* Add one to compensate for tinyint removal from enum. */
531
 
      pos[6]= field.type + 1;
 
538
      /* With conversion */
 
539
      uint32_t max_char_len;
 
540
      int2store(pos, session_charset->number);
 
541
      /*
 
542
        For TEXT/BLOB columns, field_length describes the maximum data
 
543
        length in bytes. There is no limit to the number of characters
 
544
        that a TEXT column can store, as long as the data fits into
 
545
        the designated space.
 
546
        For the rest of textual columns, field_length is evaluated as
 
547
        char_count * mbmaxlen, where character count is taken from the
 
548
        definition of the column. In other words, the maximum number
 
549
        of characters here is limited by the column definition.
 
550
      */
 
551
      max_char_len= field.length / item->collation.collation->mbmaxlen;
 
552
      int4store(pos+2, max_char_len * session_charset->mbmaxlen);
532
553
    }
533
 
 
 
554
    pos[6]= field.type;
534
555
    int2store(pos+7,field.flags);
535
556
    pos[9]= (char) field.decimals;
536
 
    pos[10]= 0;                // For the future
537
 
    pos[11]= 0;                // For the future
 
557
    pos[10]= 0;                         // For the future
 
558
    pos[11]= 0;                         // For the future
538
559
    pos+= 12;
539
560
 
540
 
    packet.length((uint32_t) (pos - packet.ptr()));
541
 
    if (flush())
542
 
      break;
 
561
    local_packet->length((uint) (pos - local_packet->ptr()));
 
562
    if (flags & SEND_DEFAULTS)
 
563
      item->send(&prot, &tmp);                  // Send default value
 
564
    if (prot.write())
 
565
      break;                                    /* purecov: inspected */
543
566
  }
544
567
 
545
 
  /*
546
 
    Mark the end of meta-data result set, and store session->server_status,
547
 
    to show that there is no cursor.
548
 
    Send no warning information, as it will be sent at statement end.
549
 
  */
550
 
  writeEOFPacket(session->server_status, session->total_warn_count);
551
 
  return 0;
 
568
  if (flags & SEND_EOF)
 
569
  {
 
570
    /*
 
571
      Mark the end of meta-data result set, and store session->server_status,
 
572
      to show that there is no cursor.
 
573
      Send no warning information, as it will be sent at statement end.
 
574
    */
 
575
    write_eof_packet(session, &session->net, session->server_status, session->total_warn_count);
 
576
  }
 
577
  return(prepare_for_send(list));
552
578
 
553
579
err:
554
580
  my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
555
 
             MYF(0));
556
 
  return 1;
557
 
}
558
 
 
559
 
bool ClientDrizzleProtocol::store(Field *from)
560
 
{
561
 
  if (from->is_null())
562
 
    return store();
563
 
  char buff[MAX_FIELD_WIDTH];
564
 
  String str(buff,sizeof(buff), &my_charset_bin);
565
 
 
566
 
  from->val_str(&str);
567
 
 
568
 
  return netStoreData((const unsigned char *)str.ptr(), str.length());
569
 
}
570
 
 
571
 
bool ClientDrizzleProtocol::store(void)
 
581
             MYF(0));   /* purecov: inspected */
 
582
  return(1);                            /* purecov: inspected */
 
583
}
 
584
 
 
585
 
 
586
bool Protocol::write()
 
587
{
 
588
  return(my_net_write(&session->net, (unsigned char*) packet->ptr(),
 
589
                           packet->length()));
 
590
}
 
591
 
 
592
 
 
593
/**
 
594
  Send \\0 end terminated string.
 
595
 
 
596
  @param from   NULL or \\0 terminated string
 
597
 
 
598
  @note
 
599
    In most cases one should use store(from, length) instead of this function
 
600
 
 
601
  @retval
 
602
    0           ok
 
603
  @retval
 
604
    1           error
 
605
*/
 
606
 
 
607
bool Protocol::store(const char *from, const CHARSET_INFO * const cs)
 
608
{
 
609
  if (!from)
 
610
    return store_null();
 
611
  uint32_t length= strlen(from);
 
612
  return store(from, length, cs);
 
613
}
 
614
 
 
615
 
 
616
/**
 
617
  Send a set of strings as one long string with ',' in between.
 
618
*/
 
619
 
 
620
bool Protocol::store(I_List<i_string>* str_list)
 
621
{
 
622
  char buf[256];
 
623
  String tmp(buf, sizeof(buf), &my_charset_bin);
 
624
  uint32_t len;
 
625
  I_List_iterator<i_string> it(*str_list);
 
626
  i_string* s;
 
627
 
 
628
  tmp.length(0);
 
629
  while ((s=it++))
 
630
  {
 
631
    tmp.append(s->ptr);
 
632
    tmp.append(',');
 
633
  }
 
634
  if ((len= tmp.length()))
 
635
    len--;                                      // Remove last ','
 
636
  return store((char*) tmp.ptr(), len,  tmp.charset());
 
637
}
 
638
 
 
639
 
 
640
bool Protocol::store(String *str)
 
641
{
 
642
  return store((char*) str->ptr(), str->length(), str->charset());
 
643
}
 
644
 
 
645
void Protocol::free()
 
646
{
 
647
  packet->free();
 
648
}
 
649
 
 
650
 
 
651
/****************************************************************************
 
652
  Functions to handle the simple (default) protocol where everything is
 
653
  This protocol is the one that is used by default between the MySQL server
 
654
  and client when you are not using prepared statements.
 
655
 
 
656
  All data are sent as 'packed-string-length' followed by 'string-data'
 
657
****************************************************************************/
 
658
 
 
659
void Protocol_text::prepare_for_resend()
 
660
{
 
661
  packet->length(0);
 
662
}
 
663
 
 
664
bool Protocol_text::store_null()
572
665
{
573
666
  char buff[1];
574
667
  buff[0]= (char)251;
575
 
  return packet.append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
576
 
}
577
 
 
578
 
bool ClientDrizzleProtocol::store(int32_t from)
579
 
{
580
 
  char buff[12];
581
 
  return netStoreData((unsigned char*) buff,
582
 
                      (size_t) (internal::int10_to_str(from, buff, -10) - buff));
583
 
}
584
 
 
585
 
bool ClientDrizzleProtocol::store(uint32_t from)
586
 
{
587
 
  char buff[11];
588
 
  return netStoreData((unsigned char*) buff,
589
 
                      (size_t) (internal::int10_to_str(from, buff, 10) - buff));
590
 
}
591
 
 
592
 
bool ClientDrizzleProtocol::store(int64_t from)
 
668
  return packet->append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
 
669
}
 
670
 
 
671
 
 
672
/**
 
673
  Auxilary function to convert string to the given character set
 
674
  and store in network buffer.
 
675
*/
 
676
 
 
677
bool Protocol::store_string_aux(const char *from, size_t length,
 
678
                                const CHARSET_INFO * const fromcs,
 
679
                                                                const CHARSET_INFO * const tocs)
 
680
{
 
681
  /* 'tocs' is set 0 when client issues SET character_set_results=NULL */
 
682
  if (tocs && !my_charset_same(fromcs, tocs) &&
 
683
      fromcs != &my_charset_bin &&
 
684
      tocs != &my_charset_bin)
 
685
  {
 
686
    /* Store with conversion */
 
687
    return net_store_data((unsigned char*) from, length, fromcs, tocs);
 
688
  }
 
689
  /* Store without conversion */
 
690
  return net_store_data((unsigned char*) from, length);
 
691
}
 
692
 
 
693
 
 
694
bool Protocol_text::store(const char *from, size_t length,
 
695
                          const CHARSET_INFO * const fromcs,
 
696
                                                  const CHARSET_INFO * const tocs)
 
697
{
 
698
  return store_string_aux(from, length, fromcs, tocs);
 
699
}
 
700
 
 
701
 
 
702
bool Protocol_text::store(const char *from, size_t length,
 
703
                          const CHARSET_INFO * const fromcs)
 
704
{
 
705
  const CHARSET_INFO * const tocs= default_charset_info;
 
706
  return store_string_aux(from, length, fromcs, tocs);
 
707
}
 
708
 
 
709
 
 
710
bool Protocol_text::store_tiny(int64_t from)
 
711
{
 
712
  char buff[20];
 
713
  return net_store_data((unsigned char*) buff,
 
714
                        (size_t) (int10_to_str((int) from, buff, -10) - buff));
 
715
}
 
716
 
 
717
 
 
718
bool Protocol_text::store_short(int64_t from)
 
719
{
 
720
  char buff[20];
 
721
  return net_store_data((unsigned char*) buff,
 
722
                        (size_t) (int10_to_str((int) from, buff, -10) -
 
723
                                  buff));
 
724
}
 
725
 
 
726
 
 
727
bool Protocol_text::store_long(int64_t from)
 
728
{
 
729
  char buff[20];
 
730
  return net_store_data((unsigned char*) buff,
 
731
                        (size_t) (int10_to_str((long int)from, buff,
 
732
                                               (from <0)?-10:10)-buff));
 
733
}
 
734
 
 
735
 
 
736
bool Protocol_text::store_int64_t(int64_t from, bool unsigned_flag)
593
737
{
594
738
  char buff[22];
595
 
  return netStoreData((unsigned char*) buff,
596
 
                      (size_t) (internal::int64_t10_to_str(from, buff, -10) - buff));
597
 
}
598
 
 
599
 
bool ClientDrizzleProtocol::store(uint64_t from)
600
 
{
601
 
  char buff[21];
602
 
  return netStoreData((unsigned char*) buff,
603
 
                      (size_t) (internal::int64_t10_to_str(from, buff, 10) - buff));
604
 
}
605
 
 
606
 
bool ClientDrizzleProtocol::store(double from, uint32_t decimals, String *buffer)
 
739
  return net_store_data((unsigned char*) buff,
 
740
                        (size_t) (int64_t10_to_str(from,buff,
 
741
                                                    unsigned_flag ? 10 : -10)-
 
742
                                  buff));
 
743
}
 
744
 
 
745
 
 
746
bool Protocol_text::store_decimal(const my_decimal *d)
 
747
{
 
748
  char buff[DECIMAL_MAX_STR_LENGTH];
 
749
  String str(buff, sizeof(buff), &my_charset_bin);
 
750
  (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
 
751
  return net_store_data((unsigned char*) str.ptr(), str.length());
 
752
}
 
753
 
 
754
 
 
755
bool Protocol_text::store(float from, uint32_t decimals, String *buffer)
 
756
{
 
757
  buffer->set_real((double) from, decimals, session->charset());
 
758
  return net_store_data((unsigned char*) buffer->ptr(), buffer->length());
 
759
}
 
760
 
 
761
 
 
762
bool Protocol_text::store(double from, uint32_t decimals, String *buffer)
607
763
{
608
764
  buffer->set_real(from, decimals, session->charset());
609
 
  return netStoreData((unsigned char*) buffer->ptr(), buffer->length());
610
 
}
611
 
 
612
 
bool ClientDrizzleProtocol::store(const char *from, size_t length)
613
 
{
614
 
  return netStoreData((const unsigned char *)from, length);
615
 
}
616
 
 
617
 
bool ClientDrizzleProtocol::wasAborted(void)
618
 
{
619
 
  return net.error && net.vio != 0;
620
 
}
621
 
 
622
 
bool ClientDrizzleProtocol::haveMoreData(void)
623
 
{
624
 
  return drizzleclient_net_more_data(&net);
625
 
}
626
 
 
627
 
bool ClientDrizzleProtocol::haveError(void)
628
 
{
629
 
  return net.error || net.vio == 0;
630
 
}
631
 
 
632
 
bool ClientDrizzleProtocol::checkConnection(void)
633
 
{
634
 
  uint32_t pkt_len= 0;
635
 
  char *end;
636
 
 
637
 
  // TCP/IP connection
638
 
  {
639
 
    char ip[NI_MAXHOST];
640
 
    uint16_t peer_port;
641
 
 
642
 
    if (drizzleclient_net_peer_addr(&net, ip, &peer_port, NI_MAXHOST))
643
 
    {
644
 
      my_error(ER_BAD_HOST_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
645
 
      return false;
646
 
    }
647
 
 
648
 
    session->getSecurityContext().setIp(ip);
649
 
  }
650
 
  drizzleclient_net_keepalive(&net, true);
651
 
 
652
 
  uint32_t server_capabilites;
653
 
  {
654
 
    /* buff[] needs to big enough to hold the server_version variable */
655
 
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
656
 
 
657
 
    server_capabilites= CLIENT_BASIC_FLAGS;
658
 
 
659
 
    if (using_mysql41_protocol)
660
 
      server_capabilites|= CLIENT_PROTOCOL_MYSQL41;
661
 
 
662
 
#ifdef HAVE_COMPRESS
663
 
    server_capabilites|= CLIENT_COMPRESS;
664
 
#endif /* HAVE_COMPRESS */
665
 
 
666
 
    end= buff + strlen(VERSION);
667
 
    if ((end - buff) >= SERVER_VERSION_LENGTH)
668
 
      end= buff + (SERVER_VERSION_LENGTH - 1);
669
 
    memcpy(buff, VERSION, end - buff);
670
 
    *end= 0;
671
 
    end++;
672
 
 
673
 
    int4store((unsigned char*) end, global_thread_id);
674
 
    end+= 4;
675
 
 
676
 
    /* We don't use scramble anymore. */
677
 
    memset(end, 'X', SCRAMBLE_LENGTH_323);
678
 
    end+= SCRAMBLE_LENGTH_323;
679
 
    *end++= 0; /* an empty byte for some reason */
680
 
 
681
 
    int2store(end, server_capabilites);
682
 
    /* write server characteristics: up to 16 bytes allowed */
683
 
    end[2]=(char) default_charset_info->number;
684
 
    int2store(end+3, session->server_status);
685
 
    memset(end+5, 0, 13);
686
 
    end+= 18;
687
 
 
688
 
    /* Write scramble tail. */
689
 
    memset(end, 'X', SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
690
 
    end+= (SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
691
 
    *end++= 0; /* an empty byte for some reason */
692
 
 
693
 
    /* At this point we write connection message and read reply */
694
 
    if (drizzleclient_net_write_command(&net
695
 
          , (unsigned char) PROTOCOL_VERSION
696
 
          , (unsigned char*) ""
697
 
          , 0
698
 
          , (unsigned char*) buff
699
 
          , (size_t) (end-buff)) 
700
 
        ||    (pkt_len= drizzleclient_net_read(&net)) == packet_error 
701
 
        || pkt_len < MIN_HANDSHAKE_SIZE)
702
 
    {
703
 
      my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
704
 
      return false;
705
 
    }
706
 
  }
707
 
  if (packet.alloc(buffer_length))
708
 
    return false; /* The error is set by alloc(). */
709
 
 
710
 
  client_capabilities= uint2korr(net.read_pos);
711
 
 
712
 
 
713
 
  client_capabilities|= ((uint32_t) uint2korr(net.read_pos + 2)) << 16;
714
 
  session->max_client_packet_length= uint4korr(net.read_pos + 4);
715
 
  end= (char*) net.read_pos + 32;
716
 
 
717
 
  /*
718
 
    Disable those bits which are not supported by the server.
719
 
    This is a precautionary measure, if the client lies. See Bug#27944.
720
 
  */
721
 
  client_capabilities&= server_capabilites;
722
 
 
723
 
  if (end >= (char*) net.read_pos + pkt_len + 2)
724
 
  {
725
 
    my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
726
 
    return false;
727
 
  }
728
 
 
729
 
  net.return_status= &session->server_status;
730
 
 
731
 
  char *user= end;
732
 
  char *passwd= strchr(user, '\0')+1;
733
 
  uint32_t user_len= passwd - user - 1;
734
 
  char *l_db= passwd;
735
 
 
736
 
  /*
737
 
    Old clients send null-terminated string as password; new clients send
738
 
    the size (1 byte) + string (not null-terminated). Hence in case of empty
739
 
    password both send '\0'.
740
 
 
741
 
    This strlen() can't be easily deleted without changing client.
742
 
 
743
 
    Cast *passwd to an unsigned char, so that it doesn't extend the sign for
744
 
    *passwd > 127 and become 2**32-127+ after casting to uint.
745
 
  */
746
 
  uint32_t passwd_len= client_capabilities & CLIENT_SECURE_CONNECTION ?
747
 
    (unsigned char)(*passwd++) : strlen(passwd);
748
 
  l_db= client_capabilities & CLIENT_CONNECT_WITH_DB ? l_db + passwd_len + 1 : 0;
749
 
 
750
 
  /* strlen() can't be easily deleted without changing client */
751
 
  uint32_t db_len= l_db ? strlen(l_db) : 0;
752
 
 
753
 
  if (passwd + passwd_len + db_len > (char *) net.read_pos + pkt_len)
754
 
  {
755
 
    my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
756
 
    return false;
757
 
  }
758
 
 
759
 
  /* If username starts and ends in "'", chop them off */
760
 
  if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
761
 
  {
762
 
    user[user_len-1]= 0;
763
 
    user++;
764
 
    user_len-= 2;
765
 
  }
766
 
 
767
 
  session->getSecurityContext().setUser(user);
768
 
 
769
 
  return session->checkUser(passwd, passwd_len, l_db);
770
 
}
771
 
 
772
 
bool ClientDrizzleProtocol::netStoreData(const unsigned char *from, size_t length)
773
 
{
774
 
  size_t packet_length= packet.length();
775
 
  /*
776
 
     The +9 comes from that strings of length longer than 16M require
777
 
     9 bytes to be stored (see drizzleclient_net_store_length).
778
 
  */
779
 
  if (packet_length+9+length > packet.alloced_length() &&
780
 
      packet.realloc(packet_length+9+length))
781
 
    return 1;
782
 
  unsigned char *to= drizzleclient_net_store_length((unsigned char*) packet.ptr()+packet_length, length);
783
 
  memcpy(to,from,length);
784
 
  packet.length((size_t) (to+length-(unsigned char*) packet.ptr()));
785
 
  return 0;
786
 
}
787
 
 
788
 
/**
789
 
  Format EOF packet according to the current client and
790
 
  write it to the network output buffer.
791
 
*/
792
 
 
793
 
void ClientDrizzleProtocol::writeEOFPacket(uint32_t server_status,
794
 
                                         uint32_t total_warn_count)
795
 
{
796
 
  unsigned char buff[5];
797
 
  /*
798
 
    Don't send warn count during SP execution, as the warn_list
799
 
    is cleared between substatements, and mysqltest gets confused
800
 
  */
801
 
  uint32_t tmp= min(total_warn_count, (uint32_t)65535);
802
 
  buff[0]= DRIZZLE_PROTOCOL_NO_MORE_DATA;
803
 
  int2store(buff+1, tmp);
804
 
  /*
805
 
    The following test should never be true, but it's better to do it
806
 
    because if 'is_fatal_error' is set the server is not going to execute
807
 
    other queries (see the if test in dispatch_command / COM_QUERY)
808
 
  */
809
 
  if (session->is_fatal_error)
810
 
    server_status&= ~SERVER_MORE_RESULTS_EXISTS;
811
 
  int2store(buff + 3, server_status);
812
 
  drizzleclient_net_write(&net, buff, 5);
813
 
}
814
 
 
815
 
static ListenDrizzleProtocol *listen_obj= NULL;
816
 
 
817
 
static int init(plugin::Context &context)
818
 
{
819
 
  listen_obj= new ListenDrizzleProtocol("drizzle_protocol", false);
820
 
  context.add(listen_obj); 
821
 
  return 0;
822
 
}
823
 
 
824
 
static DRIZZLE_SYSVAR_UINT(port, port, PLUGIN_VAR_RQCMDARG,
825
 
                           N_("Port number to use for connection or 0 for "
826
 
                              "default to, in order of "
827
 
                              "preference, drizzle.cnf, $DRIZZLE_TCP_PORT, "
828
 
                              "built-in default (4427)."),
829
 
                           NULL, NULL, 0, 0, 65535, 0);
830
 
static DRIZZLE_SYSVAR_UINT(connect_timeout, connect_timeout,
831
 
                           PLUGIN_VAR_RQCMDARG, N_("Connect Timeout."),
832
 
                           NULL, NULL, 10, 1, 300, 0);
833
 
static DRIZZLE_SYSVAR_UINT(read_timeout, read_timeout, PLUGIN_VAR_RQCMDARG,
834
 
                           N_("Read Timeout."), NULL, NULL, 30, 1, 300, 0);
835
 
static DRIZZLE_SYSVAR_UINT(write_timeout, write_timeout, PLUGIN_VAR_RQCMDARG,
836
 
                           N_("Write Timeout."), NULL, NULL, 60, 1, 300, 0);
837
 
static DRIZZLE_SYSVAR_UINT(retry_count, retry_count, PLUGIN_VAR_RQCMDARG,
838
 
                           N_("Retry Count."), NULL, NULL, 10, 1, 100, 0);
839
 
static DRIZZLE_SYSVAR_UINT(buffer_length, buffer_length, PLUGIN_VAR_RQCMDARG,
840
 
                           N_("Buffer length."), NULL, NULL, 16384, 1024,
841
 
                           1024*1024, 0);
842
 
static DRIZZLE_SYSVAR_STR(bind_address, bind_address, PLUGIN_VAR_READONLY,
843
 
                          N_("Address to bind to."), NULL, NULL, NULL);
844
 
 
845
 
static drizzle_sys_var* sys_variables[]= {
846
 
  DRIZZLE_SYSVAR(port),
847
 
  DRIZZLE_SYSVAR(connect_timeout),
848
 
  DRIZZLE_SYSVAR(read_timeout),
849
 
  DRIZZLE_SYSVAR(write_timeout),
850
 
  DRIZZLE_SYSVAR(retry_count),
851
 
  DRIZZLE_SYSVAR(buffer_length),
852
 
  DRIZZLE_SYSVAR(bind_address),
853
 
  NULL
854
 
};
855
 
 
856
 
} /* namespace drizzle_protocol */
857
 
 
858
 
DRIZZLE_PLUGIN(drizzle_protocol::init, drizzle_protocol::sys_variables);
 
765
  return net_store_data((unsigned char*) buffer->ptr(), buffer->length());
 
766
}
 
767
 
 
768
 
 
769
bool Protocol_text::store(Field *field)
 
770
{
 
771
  if (field->is_null())
 
772
    return store_null();
 
773
  char buff[MAX_FIELD_WIDTH];
 
774
  String str(buff,sizeof(buff), &my_charset_bin);
 
775
  const CHARSET_INFO * const tocs= default_charset_info;
 
776
 
 
777
  field->val_str(&str);
 
778
 
 
779
  return store_string_aux(str.ptr(), str.length(), str.charset(), tocs);
 
780
}
 
781
 
 
782
 
 
783
/**
 
784
  @todo
 
785
    Second_part format ("%06") needs to change when
 
786
    we support 0-6 decimals for time.
 
787
*/
 
788
 
 
789
bool Protocol_text::store(DRIZZLE_TIME *tm)
 
790
{
 
791
  char buff[40];
 
792
  uint32_t length;
 
793
  length= sprintf(buff, "%04d-%02d-%02d %02d:%02d:%02d",
 
794
                           (int) tm->year,
 
795
                           (int) tm->month,
 
796
                           (int) tm->day,
 
797
                           (int) tm->hour,
 
798
                           (int) tm->minute,
 
799
                           (int) tm->second);
 
800
  if (tm->second_part)
 
801
    length+= sprintf(buff+length, ".%06d",
 
802
                                     (int)tm->second_part);
 
803
  return net_store_data((unsigned char*) buff, length);
 
804
}
 
805
 
 
806
 
 
807
bool Protocol_text::store_date(DRIZZLE_TIME *tm)
 
808
{
 
809
  char buff[MAX_DATE_STRING_REP_LENGTH];
 
810
  size_t length= my_date_to_str(tm, buff);
 
811
  return net_store_data((unsigned char*) buff, length);
 
812
}
 
813
 
 
814
 
 
815
/**
 
816
  @todo
 
817
    Second_part format ("%06") needs to change when
 
818
    we support 0-6 decimals for time.
 
819
*/
 
820
 
 
821
bool Protocol_text::store_time(DRIZZLE_TIME *tm)
 
822
{
 
823
  char buff[40];
 
824
  uint32_t length;
 
825
  uint32_t day= (tm->year || tm->month) ? 0 : tm->day;
 
826
  length= sprintf(buff, "%s%02ld:%02d:%02d",
 
827
                           tm->neg ? "-" : "",
 
828
                           (long) day*24L+(long) tm->hour,
 
829
                           (int) tm->minute,
 
830
                           (int) tm->second);
 
831
  if (tm->second_part)
 
832
    length+= sprintf(buff+length, ".%06d", (int)tm->second_part);
 
833
  return net_store_data((unsigned char*) buff, length);
 
834
}
 
835