~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/oldlibdrizzle/oldlibdrizzle.cc

  • Committer: Monty Taylor
  • Date: 2009-09-30 07:01:32 UTC
  • mto: This revision was merged to the branch mainline in revision 1184.
  • Revision ID: mordred@inaugust.com-20090930070132-b1ol1xu1rpajdddy
Small namespace cleanup.

Show diffs side-by-side

added added

removed removed

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