~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/oldlibdrizzle/oldlibdrizzle.cc

  • Committer: Brian Aker
  • Date: 2009-06-03 19:30:45 UTC
  • mfrom: (1046.1.6 merge)
  • Revision ID: brian@gaz-20090603193045-4xgeczyfixh07beg
MergeĀ forĀ Brian

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2010 Brian Aker
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; either version 2 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  This program is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with this program; if not, write to the Free Software
18
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
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
19
18
 */
20
19
 
21
 
 
22
 
#include "config.h"
23
 
#include <drizzled/gettext.h>
 
20
/**
 
21
  @file
 
22
 
 
23
  Low level functions for storing data to be send to the MySQL client.
 
24
  The actual communction is handled by the net_xxx functions in net_serv.cc
 
25
*/
 
26
 
 
27
#include <drizzled/server_includes.h>
24
28
#include <drizzled/error.h>
25
 
#include <drizzled/query_id.h>
26
29
#include <drizzled/sql_state.h>
 
30
#include <drizzled/protocol.h>
27
31
#include <drizzled/session.h>
28
 
#include "drizzled/internal/my_sys.h"
29
 
#include "drizzled/internal/m_string.h"
30
 
#include <algorithm>
31
 
#include <iostream>
32
 
#include <boost/program_options.hpp>
33
 
#include <drizzled/module/option_map.h>
34
 
#include "drizzled/util/tokenize.h"
35
 
#include "drizzle_protocol.h"
36
 
#include "plugin/drizzle_protocol/status_table.h"
37
 
 
38
 
namespace po= boost::program_options;
39
 
using namespace drizzled;
40
 
using namespace std;
41
 
 
42
 
namespace drizzle_plugin
43
 
{
44
 
namespace drizzle_protocol
45
 
{
46
 
 
47
 
std::vector<std::string> ClientDrizzleProtocol::drizzle_admin_ip_addresses;
48
 
static port_constraint port;
49
 
static timeout_constraint connect_timeout;
50
 
static timeout_constraint read_timeout;
51
 
static timeout_constraint write_timeout;
52
 
static retry_constraint retry_count;
53
 
static buffer_constraint buffer_length;
54
 
 
55
 
static const uint32_t DRIZZLE_TCP_PORT= 4427;
56
 
 
57
 
ProtocolCounters *ListenDrizzleProtocol::drizzle_counters= new ProtocolCounters();
58
 
 
59
 
ListenDrizzleProtocol::~ListenDrizzleProtocol()
60
 
{
61
 
}
62
 
 
63
 
in_port_t ListenDrizzleProtocol::getPort(void) const
64
 
{
65
 
  return port;
66
 
}
67
 
 
68
 
void ClientDrizzleProtocol::drizzle_compose_ip_addresses(vector<string> options)
69
 
{
70
 
  for (vector<string>::iterator it= options.begin();
71
 
       it != options.end();
72
 
       ++it)
73
 
  {
74
 
    tokenize(*it, drizzle_admin_ip_addresses, ",", true);
75
 
  }
76
 
}
77
 
 
78
 
bool ClientDrizzleProtocol::isAdminAllowed(void)
79
 
{
80
 
  if (std::find(drizzle_admin_ip_addresses.begin(), drizzle_admin_ip_addresses.end(), session->getSecurityContext().getIp()) != drizzle_admin_ip_addresses.end())
81
 
    return true;
82
 
  else
83
 
    return false;
84
 
}
85
 
 
86
 
plugin::Client *ListenDrizzleProtocol::getClient(int fd)
87
 
{
88
 
  int new_fd;
89
 
  new_fd= acceptTcp(fd);
90
 
  if (new_fd == -1)
91
 
    return NULL;
92
 
 
93
 
  return new ClientDrizzleProtocol(new_fd, getCounters());
94
 
}
95
 
 
96
 
static int init(drizzled::module::Context &context)
97
 
{  
98
 
  const module::option_map &vm= context.getOptions();
99
 
 
100
 
  context.add(new StatusTable);
101
 
  context.add(new ListenDrizzleProtocol("drizzle_protocol", vm["bind-address"].as<std::string>(), true));
102
 
  context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", port));
103
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("connect_timeout", connect_timeout));
104
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("read_timeout", read_timeout));
105
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("write_timeout", write_timeout));
106
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("retry_count", retry_count));
107
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("buffer_length", buffer_length));
108
 
  context.registerVariable(new sys_var_const_string_val("bind_address",
109
 
                                                        vm["bind-address"].as<std::string>()));
110
 
 
111
 
  context.registerVariable(new sys_var_uint32_t_ptr("max-connections", &ListenDrizzleProtocol::drizzle_counters->max_connections));
112
 
 
113
 
  return 0;
114
 
}
115
 
 
116
 
 
117
 
static void init_options(drizzled::module::option_context &context)
118
 
{
119
 
  context("port",
120
 
          po::value<port_constraint>(&port)->default_value(DRIZZLE_TCP_PORT),
121
 
          N_("Port number to use for connection or 0 for default to with Drizzle/MySQL protocol."));
122
 
  context("connect-timeout",
123
 
          po::value<timeout_constraint>(&connect_timeout)->default_value(10),
124
 
          N_("Connect Timeout."));
125
 
  context("read-timeout",
126
 
          po::value<timeout_constraint>(&read_timeout)->default_value(30),
127
 
          N_("Read Timeout."));
128
 
  context("write-timeout",
129
 
          po::value<timeout_constraint>(&write_timeout)->default_value(60),
130
 
          N_("Write Timeout."));
131
 
  context("retry-count",
132
 
          po::value<retry_constraint>(&retry_count)->default_value(10),
133
 
          N_("Retry Count."));
134
 
  context("buffer-length",
135
 
          po::value<buffer_constraint>(&buffer_length)->default_value(16384),
136
 
          N_("Buffer length."));
137
 
  context("bind-address",
138
 
          po::value<std::string>()->default_value(""),
139
 
          N_("Address to bind to."));
140
 
  context("max-connections",
141
 
          po::value<uint32_t>(&ListenDrizzleProtocol::drizzle_counters->max_connections)->default_value(1000),
142
 
          N_("Maximum simultaneous connections."));
143
 
  context("admin-ip-addresses",
144
 
          po::value<vector<string> >()->composing()->notifier(&ClientDrizzleProtocol::drizzle_compose_ip_addresses),
145
 
          N_("A restrictive IP address list for incoming admin connections."));
146
 
}
147
 
 
148
 
} /* namespace drizzle_protocol */
149
 
} /* namespace drizzle_plugin */
150
 
 
151
 
DRIZZLE_PLUGIN(drizzle_plugin::drizzle_protocol::init, NULL, drizzle_plugin::drizzle_protocol::init_options);
 
32
#include <drizzled/data_home.h>
 
33
#include "pack.h"
 
34
#include "errmsg.h"
 
35
#include "oldlibdrizzle.h"
 
36
 
 
37
/*
 
38
  Function called by drizzleclient_net_init() to set some check variables
 
39
*/
 
40
 
 
41
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
 
42
 
 
43
static void write_eof_packet(Session *session, NET *net,
 
44
                             uint32_t server_status, uint32_t total_warn_count);
 
45
 
 
46
bool ProtocolOldLibdrizzle::isConnected()
 
47
{
 
48
  return net.vio != 0;
 
49
}
 
50
 
 
51
void ProtocolOldLibdrizzle::setReadTimeout(uint32_t timeout)
 
52
{
 
53
  drizzleclient_net_set_read_timeout(&net, timeout);
 
54
}
 
55
 
 
56
void ProtocolOldLibdrizzle::setWriteTimeout(uint32_t timeout)
 
57
{
 
58
  drizzleclient_net_set_write_timeout(&net, timeout);
 
59
}
 
60
 
 
61
void ProtocolOldLibdrizzle::setRetryCount(uint32_t count)
 
62
{
 
63
  net.retry_count=count;
 
64
}
 
65
 
 
66
void ProtocolOldLibdrizzle::setError(char error)
 
67
{
 
68
  net.error= error;
 
69
}
 
70
 
 
71
bool ProtocolOldLibdrizzle::haveError(void)
 
72
{
 
73
  return net.error || net.vio == 0;
 
74
}
 
75
 
 
76
bool ProtocolOldLibdrizzle::wasAborted(void)
 
77
{
 
78
  return net.error && net.vio != 0;
 
79
}
 
80
 
 
81
bool ProtocolOldLibdrizzle::haveMoreData(void)
 
82
{
 
83
  return drizzleclient_net_more_data(&net);
 
84
}
 
85
 
 
86
void ProtocolOldLibdrizzle::enableCompression(void)
 
87
{
 
88
  net.compress= true;
 
89
}
 
90
 
 
91
bool ProtocolOldLibdrizzle::isReading(void)
 
92
{
 
93
  return net.reading_or_writing == 1;
 
94
}
 
95
 
 
96
bool ProtocolOldLibdrizzle::isWriting(void)
 
97
{
 
98
  return net.reading_or_writing == 2;
 
99
}
 
100
 
 
101
bool ProtocolOldLibdrizzle::netStoreData(const unsigned char *from, size_t length)
 
102
{
 
103
  size_t packet_length= packet->length();
 
104
  /*
 
105
     The +9 comes from that strings of length longer than 16M require
 
106
     9 bytes to be stored (see drizzleclient_net_store_length).
 
107
  */
 
108
  if (packet_length+9+length > packet->alloced_length() &&
 
109
      packet->realloc(packet_length+9+length))
 
110
    return 1;
 
111
  unsigned char *to= drizzleclient_net_store_length((unsigned char*) packet->ptr()+packet_length, length);
 
112
  memcpy(to,from,length);
 
113
  packet->length((size_t) (to+length-(unsigned char*) packet->ptr()));
 
114
  return 0;
 
115
}
 
116
 
 
117
 
 
118
/*
 
119
  netStoreData() - extended version with character set conversion.
 
120
 
 
121
  It is optimized for short strings whose length after
 
122
  conversion is garanteed to be less than 251, which accupies
 
123
  exactly one byte to store length. It allows not to use
 
124
  the "convert" member as a temporary buffer, conversion
 
125
  is done directly to the "packet" member.
 
126
  The limit 251 is good enough to optimize send_fields()
 
127
  because column, table, database names fit into this limit.
 
128
*/
 
129
 
 
130
bool ProtocolOldLibdrizzle::netStoreData(const unsigned char *from, size_t length,
 
131
                              const CHARSET_INFO * const from_cs,
 
132
                              const CHARSET_INFO * const to_cs)
 
133
{
 
134
  uint32_t dummy_errors;
 
135
  /* Calculate maxumum possible result length */
 
136
  uint32_t conv_length= to_cs->mbmaxlen * length / from_cs->mbminlen;
 
137
  if (conv_length > 250)
 
138
  {
 
139
    /*
 
140
      For strings with conv_length greater than 250 bytes
 
141
      we don't know how many bytes we will need to store length: one or two,
 
142
      because we don't know result length until conversion is done.
 
143
      For example, when converting from utf8 (mbmaxlen=3) to latin1,
 
144
      conv_length=300 means that the result length can vary between 100 to 300.
 
145
      length=100 needs one byte, length=300 needs to bytes.
 
146
 
 
147
      Thus conversion directly to "packet" is not worthy.
 
148
      Let's use "convert" as a temporary buffer.
 
149
    */
 
150
    return (convert->copy((const char*) from, length, from_cs,
 
151
                          to_cs, &dummy_errors) ||
 
152
            netStoreData((const unsigned char*) convert->ptr(), convert->length()));
 
153
  }
 
154
 
 
155
  size_t packet_length= packet->length();
 
156
  size_t new_length= packet_length + conv_length + 1;
 
157
 
 
158
  if (new_length > packet->alloced_length() && packet->realloc(new_length))
 
159
    return 1;
 
160
 
 
161
  char *length_pos= (char*) packet->ptr() + packet_length;
 
162
  char *to= length_pos + 1;
 
163
 
 
164
  to+= copy_and_convert(to, conv_length, to_cs,
 
165
                        (const char*) from, length, from_cs, &dummy_errors);
 
166
 
 
167
  drizzleclient_net_store_length((unsigned char*) length_pos, to - length_pos - 1);
 
168
  packet->length((uint32_t) (to - packet->ptr()));
 
169
  return 0;
 
170
}
 
171
 
 
172
 
 
173
/**
 
174
  Return ok to the client.
 
175
 
 
176
  The ok packet has the following structure:
 
177
 
 
178
  - 0               : Marker (1 byte)
 
179
  - affected_rows    : Stored in 1-9 bytes
 
180
  - id        : Stored in 1-9 bytes
 
181
  - server_status    : Copy of session->server_status;  Can be used by client
 
182
  to check if we are inside an transaction.
 
183
  New in 4.0 protocol
 
184
  - warning_count    : Stored in 2 bytes; New in 4.1 protocol
 
185
  - message        : Stored as packed length (1-9 bytes) + message.
 
186
  Is not stored if no message.
 
187
 
 
188
  @param session           Thread handler
 
189
  @param affected_rows       Number of rows changed by statement
 
190
  @param id           Auto_increment id for first row (if used)
 
191
  @param message       Message to send to the client (Used by mysql_status)
 
192
*/
 
193
 
 
194
void ProtocolOldLibdrizzle::sendOK()
 
195
{
 
196
  unsigned char buff[DRIZZLE_ERRMSG_SIZE+10],*pos;
 
197
  const char *message= NULL;
 
198
  uint32_t tmp;
 
199
 
 
200
  if (!net.vio)    // hack for re-parsing queries
 
201
  {
 
202
    return;
 
203
  }
 
204
 
 
205
  buff[0]=0;                    // No fields
 
206
  if (session->main_da.status() == Diagnostics_area::DA_OK)
 
207
  {
 
208
    pos=drizzleclient_net_store_length(buff+1,session->main_da.affected_rows());
 
209
    pos=drizzleclient_net_store_length(pos, session->main_da.last_insert_id());
 
210
    int2store(pos, session->main_da.server_status());
 
211
    pos+=2;
 
212
    tmp= cmin(session->main_da.total_warn_count(), (uint32_t)65535);
 
213
    message= session->main_da.message();
 
214
  }
 
215
  else
 
216
  {
 
217
    pos=drizzleclient_net_store_length(buff+1,0);
 
218
    pos=drizzleclient_net_store_length(pos, 0);
 
219
    int2store(pos, session->server_status);
 
220
    pos+=2;
 
221
    tmp= cmin(session->total_warn_count, (uint32_t)65535);
 
222
  }
 
223
 
 
224
  /* We can only return up to 65535 warnings in two bytes */
 
225
  int2store(pos, tmp);
 
226
  pos+= 2;
 
227
 
 
228
  session->main_da.can_overwrite_status= true;
 
229
 
 
230
  if (message && message[0])
 
231
  {
 
232
    size_t length= strlen(message);
 
233
    pos=drizzleclient_net_store_length(pos,length);
 
234
    memcpy(pos,(unsigned char*) message,length);
 
235
    pos+=length;
 
236
  }
 
237
  drizzleclient_net_write(&net, buff, (size_t) (pos-buff));
 
238
  drizzleclient_net_flush(&net);
 
239
 
 
240
  session->main_da.can_overwrite_status= false;
 
241
}
 
242
 
 
243
/**
 
244
  Send eof (= end of result set) to the client.
 
245
 
 
246
  The eof packet has the following structure:
 
247
 
 
248
  - 254    (DRIZZLE_PROTOCOL_NO_MORE_DATA)    : Marker (1 byte)
 
249
  - warning_count    : Stored in 2 bytes; New in 4.1 protocol
 
250
  - status_flag    : Stored in 2 bytes;
 
251
  For flags like SERVER_MORE_RESULTS_EXISTS.
 
252
 
 
253
  Note that the warning count will not be sent if 'no_flush' is set as
 
254
  we don't want to report the warning count until all data is sent to the
 
255
  client.
 
256
*/
 
257
 
 
258
void ProtocolOldLibdrizzle::sendEOF()
 
259
{
 
260
  /* Set to true if no active vio, to work well in case of --init-file */
 
261
  if (net.vio != 0)
 
262
  {
 
263
    session->main_da.can_overwrite_status= true;
 
264
    write_eof_packet(session, &net, session->main_da.server_status(),
 
265
                     session->main_da.total_warn_count());
 
266
    drizzleclient_net_flush(&net);
 
267
    session->main_da.can_overwrite_status= false;
 
268
  }
 
269
}
 
270
 
 
271
 
 
272
/**
 
273
  Format EOF packet according to the current protocol and
 
274
  write it to the network output buffer.
 
275
*/
 
276
 
 
277
static void write_eof_packet(Session *session, NET *net,
 
278
                             uint32_t server_status,
 
279
                             uint32_t total_warn_count)
 
280
{
 
281
  unsigned char buff[5];
 
282
  /*
 
283
    Don't send warn count during SP execution, as the warn_list
 
284
    is cleared between substatements, and mysqltest gets confused
 
285
  */
 
286
  uint32_t tmp= cmin(total_warn_count, (uint32_t)65535);
 
287
  buff[0]= DRIZZLE_PROTOCOL_NO_MORE_DATA;
 
288
  int2store(buff+1, tmp);
 
289
  /*
 
290
    The following test should never be true, but it's better to do it
 
291
    because if 'is_fatal_error' is set the server is not going to execute
 
292
    other queries (see the if test in dispatch_command / COM_QUERY)
 
293
  */
 
294
  if (session->is_fatal_error)
 
295
    server_status&= ~SERVER_MORE_RESULTS_EXISTS;
 
296
  int2store(buff + 3, server_status);
 
297
  drizzleclient_net_write(net, buff, 5);
 
298
}
 
299
 
 
300
void ProtocolOldLibdrizzle::sendError(uint32_t sql_errno, const char *err)
 
301
{
 
302
  uint32_t length;
 
303
  /*
 
304
    buff[]: sql_errno:2 + ('#':1 + SQLSTATE_LENGTH:5) + DRIZZLE_ERRMSG_SIZE:512
 
305
  */
 
306
  unsigned char buff[2+1+SQLSTATE_LENGTH+DRIZZLE_ERRMSG_SIZE], *pos;
 
307
 
 
308
  assert(sql_errno);
 
309
  assert(err && err[0]);
 
310
 
 
311
  /*
 
312
    It's one case when we can push an error even though there
 
313
    is an OK or EOF already.
 
314
  */
 
315
  session->main_da.can_overwrite_status= true;
 
316
 
 
317
  /* Abort multi-result sets */
 
318
  session->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
 
319
 
 
320
  /**
 
321
    Send a error string to client.
 
322
 
 
323
    For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
 
324
    critical that every error that can be intercepted is issued in one
 
325
    place only, my_message_sql.
 
326
  */
 
327
 
 
328
  if (net.vio == 0)
 
329
  {
 
330
    return;
 
331
  }
 
332
 
 
333
  int2store(buff,sql_errno);
 
334
  pos= buff+2;
 
335
 
 
336
  /* The first # is to make the protocol backward compatible */
 
337
  buff[2]= '#';
 
338
  pos= (unsigned char*) strcpy((char*) buff+3, drizzle_errno_to_sqlstate(sql_errno));
 
339
  pos+= strlen(drizzle_errno_to_sqlstate(sql_errno));
 
340
 
 
341
  char *tmp= strncpy((char*)pos, err, DRIZZLE_ERRMSG_SIZE-1);
 
342
  tmp+= strlen((char*)pos);
 
343
  tmp[0]= '\0';
 
344
  length= (uint32_t)(tmp-(char*)buff);
 
345
  err= (char*) buff;
 
346
 
 
347
  drizzleclient_net_write_command(&net,(unsigned char) 255, (unsigned char*) "", 0, (unsigned char*) err, length);
 
348
 
 
349
  session->main_da.can_overwrite_status= false;
 
350
}
 
351
 
 
352
 
 
353
ProtocolOldLibdrizzle::ProtocolOldLibdrizzle()
 
354
{
 
355
  scramble[0]= 0;
 
356
  net.vio= 0;
 
357
}
 
358
 
 
359
void ProtocolOldLibdrizzle::setSession(Session *session_arg)
 
360
{
 
361
  session= session_arg;
 
362
  packet= &session->packet;
 
363
  convert= &session->convert_buffer;
 
364
}
 
365
 
 
366
 
 
367
/**
 
368
  Send name and type of result to client.
 
369
 
 
370
  Sum fields has table name empty and field_name.
 
371
 
 
372
  @param Session        Thread data object
 
373
  @param list            List of items to send to client
 
374
  @param flag            Bit mask with the following functions:
 
375
                        - 1 send number of rows
 
376
                        - 2 send default values
 
377
                        - 4 don't write eof packet
 
378
 
 
379
  @retval
 
380
    0    ok
 
381
  @retval
 
382
    1    Error  (Note that in this case the error is not sent to the
 
383
    client)
 
384
*/
 
385
bool ProtocolOldLibdrizzle::sendFields(List<Item> *list, uint32_t flags)
 
386
{
 
387
  List_iterator_fast<Item> it(*list);
 
388
  Item *item;
 
389
  unsigned char buff[80];
 
390
  String tmp((char*) buff,sizeof(buff),&my_charset_bin);
 
391
 
 
392
  if (flags & SEND_NUM_ROWS)
 
393
  {                // Packet with number of elements
 
394
    unsigned char *pos= drizzleclient_net_store_length(buff, list->elements);
 
395
    (void) drizzleclient_net_write(&net, buff, (size_t) (pos-buff));
 
396
  }
 
397
 
 
398
  while ((item=it++))
 
399
  {
 
400
    char *pos;
 
401
    const CHARSET_INFO * const cs= system_charset_info;
 
402
    Send_field field;
 
403
    item->make_field(&field);
 
404
 
 
405
    prepareForResend();
 
406
 
 
407
    if (store(STRING_WITH_LEN("def"), cs) ||
 
408
        store(field.db_name, cs) ||
 
409
        store(field.table_name, cs) ||
 
410
        store(field.org_table_name, cs) ||
 
411
        store(field.col_name, cs) ||
 
412
        store(field.org_col_name, cs) ||
 
413
        packet->realloc(packet->length()+12))
 
414
      goto err;
 
415
 
 
416
    /* Store fixed length fields */
 
417
    pos= (char*) packet->ptr()+packet->length();
 
418
    *pos++= 12;                // Length of packed fields
 
419
    if (item->collation.collation == &my_charset_bin)
 
420
    {
 
421
      /* No conversion */
 
422
      int2store(pos, field.charsetnr);
 
423
      int4store(pos+2, field.length);
 
424
    }
 
425
    else
 
426
    {
 
427
      /* With conversion */
 
428
      uint32_t max_char_len;
 
429
      int2store(pos, cs->number);
 
430
      /*
 
431
        For TEXT/BLOB columns, field_length describes the maximum data
 
432
        length in bytes. There is no limit to the number of characters
 
433
        that a TEXT column can store, as long as the data fits into
 
434
        the designated space.
 
435
        For the rest of textual columns, field_length is evaluated as
 
436
        char_count * mbmaxlen, where character count is taken from the
 
437
        definition of the column. In other words, the maximum number
 
438
        of characters here is limited by the column definition.
 
439
      */
 
440
      max_char_len= field.length / item->collation.collation->mbmaxlen;
 
441
      int4store(pos+2, max_char_len * cs->mbmaxlen);
 
442
    }
 
443
    pos[6]= field.type;
 
444
    int2store(pos+7,field.flags);
 
445
    pos[9]= (char) field.decimals;
 
446
    pos[10]= 0;                // For the future
 
447
    pos[11]= 0;                // For the future
 
448
    pos+= 12;
 
449
 
 
450
    packet->length((uint32_t) (pos - packet->ptr()));
 
451
    if (flags & SEND_DEFAULTS)
 
452
      item->send(this, &tmp);            // Send default value
 
453
    if (write())
 
454
      break;                    /* purecov: inspected */
 
455
  }
 
456
 
 
457
  if (flags & SEND_EOF)
 
458
  {
 
459
    /*
 
460
      Mark the end of meta-data result set, and store session->server_status,
 
461
      to show that there is no cursor.
 
462
      Send no warning information, as it will be sent at statement end.
 
463
    */
 
464
    write_eof_packet(session, &net, session->server_status, session->total_warn_count);
 
465
  }
 
466
 
 
467
  field_count= list->elements;
 
468
  return 0;
 
469
 
 
470
err:
 
471
  my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
 
472
             MYF(0));    /* purecov: inspected */
 
473
  return 1;                /* purecov: inspected */
 
474
}
 
475
 
 
476
 
 
477
bool ProtocolOldLibdrizzle::write()
 
478
{
 
479
  return(drizzleclient_net_write(&net, (unsigned char*) packet->ptr(),
 
480
                           packet->length()));
 
481
}
 
482
 
 
483
void ProtocolOldLibdrizzle::free()
 
484
{
 
485
  packet->free();
 
486
}
 
487
 
 
488
 
 
489
void ProtocolOldLibdrizzle::setRandom(uint64_t seed1, uint64_t seed2)
 
490
{
 
491
  drizzleclient_randominit(&rand, seed1, seed2);
 
492
}
 
493
 
 
494
bool ProtocolOldLibdrizzle::setFileDescriptor(int fd)
 
495
{
 
496
  if (drizzleclient_net_init_sock(&net, fd, 0))
 
497
    return true;
 
498
  return false;
 
499
}
 
500
 
 
501
int ProtocolOldLibdrizzle::fileDescriptor(void)
 
502
{
 
503
  return drizzleclient_net_get_sd(&net);
 
504
}
 
505
 
 
506
bool ProtocolOldLibdrizzle::authenticate()
 
507
{
 
508
  bool connection_is_valid;
 
509
 
 
510
  /* Use "connect_timeout" value during connection phase */
 
511
  drizzleclient_net_set_read_timeout(&net, connect_timeout);
 
512
  drizzleclient_net_set_write_timeout(&net, connect_timeout);
 
513
 
 
514
  connection_is_valid= checkConnection();
 
515
 
 
516
  if (connection_is_valid)
 
517
    sendOK();
 
518
  else
 
519
  {
 
520
    sendError(session->main_da.sql_errno(), session->main_da.message());
 
521
    return false;
 
522
  }
 
523
 
 
524
  /* Connect completed, set read/write timeouts back to default */
 
525
  drizzleclient_net_set_read_timeout(&net,
 
526
                                     session->variables.net_read_timeout);
 
527
  drizzleclient_net_set_write_timeout(&net,
 
528
                                      session->variables.net_write_timeout);
 
529
  return true;
 
530
}
 
531
 
 
532
bool ProtocolOldLibdrizzle::readCommand(char **l_packet, uint32_t *packet_length)
 
533
{
 
534
  /*
 
535
    This thread will do a blocking read from the client which
 
536
    will be interrupted when the next command is received from
 
537
    the client, the connection is closed or "net_wait_timeout"
 
538
    number of seconds has passed
 
539
  */
 
540
#ifdef NEVER
 
541
  /* We can do this much more efficiently with poll timeouts or watcher thread,
 
542
     disabling for now, which means net_wait_timeout == read_timeout. */
 
543
  drizzleclient_net_set_read_timeout(&net,
 
544
                                     session->variables.net_wait_timeout);
 
545
#endif
 
546
 
 
547
  session->clear_error();
 
548
  session->main_da.reset_diagnostics_area();
 
549
 
 
550
  net.pkt_nr=0;
 
551
 
 
552
  *packet_length= drizzleclient_net_read(&net);
 
553
  if (*packet_length == packet_error)
 
554
  {
 
555
    /* Check if we can continue without closing the connection */
 
556
 
 
557
    if(net.last_errno== CR_NET_PACKET_TOO_LARGE)
 
558
      my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
 
559
    if (session->main_da.status() == Diagnostics_area::DA_ERROR)
 
560
      sendError(session->main_da.sql_errno(), session->main_da.message());
 
561
    else
 
562
      session->protocol->sendOK();
 
563
 
 
564
    if (net.error != 3)
 
565
      return false;                       // We have to close it.
 
566
 
 
567
    net.error= 0;
 
568
    *packet_length= 0;
 
569
    return true;
 
570
  }
 
571
 
 
572
  *l_packet= (char*) net.read_pos;
 
573
 
 
574
  /*
 
575
    'packet_length' contains length of data, as it was stored in packet
 
576
    header. In case of malformed header, drizzleclient_net_read returns zero.
 
577
    If packet_length is not zero, drizzleclient_net_read ensures that the returned
 
578
    number of bytes was actually read from network.
 
579
    There is also an extra safety measure in drizzleclient_net_read:
 
580
    it sets packet[packet_length]= 0, but only for non-zero packets.
 
581
  */
 
582
 
 
583
  if (*packet_length == 0)                       /* safety */
 
584
  {
 
585
    /* Initialize with COM_SLEEP packet */
 
586
    (*l_packet)[0]= (unsigned char) COM_SLEEP;
 
587
    *packet_length= 1;
 
588
  }
 
589
  /* Do not rely on drizzleclient_net_read, extra safety against programming errors. */
 
590
  (*l_packet)[*packet_length]= '\0';                  /* safety */
 
591
 
 
592
#ifdef NEVER
 
593
  /* See comment above. */
 
594
  /* Restore read timeout value */
 
595
  drizzleclient_net_set_read_timeout(&net,
 
596
                                     session->variables.net_read_timeout);
 
597
#endif
 
598
 
 
599
  return true;
 
600
}
 
601
 
 
602
void ProtocolOldLibdrizzle::close(void)
 
603
{
 
604
  if (net.vio)
 
605
  { 
 
606
    drizzleclient_net_close(&net);
 
607
    drizzleclient_net_end(&net);
 
608
  }
 
609
}
 
610
 
 
611
void ProtocolOldLibdrizzle::forceClose(void)
 
612
{
 
613
  if (net.vio)
 
614
    drizzleclient_vio_close(net.vio);
 
615
}
 
616
 
 
617
void ProtocolOldLibdrizzle::prepareForResend()
 
618
{
 
619
  packet->length(0);
 
620
}
 
621
 
 
622
bool ProtocolOldLibdrizzle::store(void)
 
623
{
 
624
  char buff[1];
 
625
  buff[0]= (char)251;
 
626
  return packet->append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
 
627
}
 
628
 
 
629
 
 
630
/**
 
631
  Auxilary function to convert string to the given character set
 
632
  and store in network buffer.
 
633
*/
 
634
 
 
635
bool ProtocolOldLibdrizzle::storeString(const char *from, size_t length,
 
636
                                        const CHARSET_INFO * const fromcs,
 
637
                                        const CHARSET_INFO * const tocs)
 
638
{
 
639
  /* 'tocs' is set 0 when client issues SET character_set_results=NULL */
 
640
  if (tocs && !my_charset_same(fromcs, tocs) &&
 
641
      fromcs != &my_charset_bin &&
 
642
      tocs != &my_charset_bin)
 
643
  {
 
644
    /* Store with conversion */
 
645
    return netStoreData((unsigned char*) from, length, fromcs, tocs);
 
646
  }
 
647
  /* Store without conversion */
 
648
  return netStoreData((unsigned char*) from, length);
 
649
}
 
650
 
 
651
 
 
652
bool ProtocolOldLibdrizzle::store(const char *from, size_t length,
 
653
                          const CHARSET_INFO * const fromcs)
 
654
{
 
655
  const CHARSET_INFO * const tocs= default_charset_info;
 
656
  return storeString(from, length, fromcs, tocs);
 
657
}
 
658
 
 
659
 
 
660
bool ProtocolOldLibdrizzle::store(int32_t from)
 
661
{
 
662
  char buff[12];
 
663
  return netStoreData((unsigned char*) buff,
 
664
                      (size_t) (int10_to_str(from, buff, -10) - buff));
 
665
}
 
666
 
 
667
bool ProtocolOldLibdrizzle::store(uint32_t from)
 
668
{
 
669
  char buff[11];
 
670
  return netStoreData((unsigned char*) buff,
 
671
                      (size_t) (int10_to_str(from, buff, 10) - buff));
 
672
}
 
673
 
 
674
bool ProtocolOldLibdrizzle::store(int64_t from)
 
675
{
 
676
  char buff[22];
 
677
  return netStoreData((unsigned char*) buff,
 
678
                      (size_t) (int64_t10_to_str(from, buff, -10) - buff));
 
679
}
 
680
 
 
681
bool ProtocolOldLibdrizzle::store(uint64_t from)
 
682
{
 
683
  char buff[21];
 
684
  return netStoreData((unsigned char*) buff,
 
685
                      (size_t) (int64_t10_to_str(from, buff, 10) - buff));
 
686
}
 
687
 
 
688
 
 
689
bool ProtocolOldLibdrizzle::store(double from, uint32_t decimals, String *buffer)
 
690
{
 
691
  buffer->set_real(from, decimals, session->charset());
 
692
  return netStoreData((unsigned char*) buffer->ptr(), buffer->length());
 
693
}
 
694
 
 
695
 
 
696
bool ProtocolOldLibdrizzle::store(Field *from)
 
697
{
 
698
  if (from->is_null())
 
699
    return store();
 
700
  char buff[MAX_FIELD_WIDTH];
 
701
  String str(buff,sizeof(buff), &my_charset_bin);
 
702
  const CHARSET_INFO * const tocs= default_charset_info;
 
703
 
 
704
  from->val_str(&str);
 
705
 
 
706
  return storeString(str.ptr(), str.length(), str.charset(), tocs);
 
707
}
 
708
 
 
709
 
 
710
/**
 
711
  @todo
 
712
    Second_part format ("%06") needs to change when
 
713
    we support 0-6 decimals for time.
 
714
*/
 
715
 
 
716
bool ProtocolOldLibdrizzle::store(const DRIZZLE_TIME *tm)
 
717
{
 
718
  char buff[40];
 
719
  uint32_t length;
 
720
  uint32_t day;
 
721
 
 
722
  switch (tm->time_type)
 
723
  {
 
724
  case DRIZZLE_TIMESTAMP_DATETIME:
 
725
    length= sprintf(buff, "%04d-%02d-%02d %02d:%02d:%02d",
 
726
                    (int) tm->year,
 
727
                    (int) tm->month,
 
728
                    (int) tm->day,
 
729
                    (int) tm->hour,
 
730
                    (int) tm->minute,
 
731
                    (int) tm->second);
 
732
    if (tm->second_part)
 
733
      length+= sprintf(buff+length, ".%06d", (int)tm->second_part);
 
734
    break;
 
735
 
 
736
  case DRIZZLE_TIMESTAMP_DATE:
 
737
    length= sprintf(buff, "%04d-%02d-%02d",
 
738
                    (int) tm->year,
 
739
                    (int) tm->month,
 
740
                    (int) tm->day);
 
741
    break;
 
742
 
 
743
  case DRIZZLE_TIMESTAMP_TIME:
 
744
    day= (tm->year || tm->month) ? 0 : tm->day;
 
745
    length= sprintf(buff, "%s%02ld:%02d:%02d", tm->neg ? "-" : "",
 
746
                    (long) day*24L+(long) tm->hour, (int) tm->minute,
 
747
                    (int) tm->second);
 
748
    if (tm->second_part)
 
749
      length+= sprintf(buff+length, ".%06d", (int)tm->second_part);
 
750
    break;
 
751
 
 
752
  case DRIZZLE_TIMESTAMP_NONE:
 
753
  case DRIZZLE_TIMESTAMP_ERROR:
 
754
  default:
 
755
    assert(0);
 
756
    return false;
 
757
  }
 
758
 
 
759
  return netStoreData((unsigned char*) buff, length);
 
760
}
 
761
 
 
762
bool ProtocolOldLibdrizzle::checkConnection(void)
 
763
{
 
764
  uint32_t pkt_len= 0;
 
765
  char *end;
 
766
 
 
767
  // TCP/IP connection
 
768
  {
 
769
    char ip[NI_MAXHOST];
 
770
 
 
771
    if (drizzleclient_net_peer_addr(&net, ip, &session->peer_port, NI_MAXHOST))
 
772
    {
 
773
      my_error(ER_BAD_HOST_ERROR, MYF(0), session->security_ctx.ip.c_str());
 
774
      return false;
 
775
    }
 
776
 
 
777
    session->security_ctx.ip.assign(ip);
 
778
  }
 
779
  drizzleclient_net_keepalive(&net, true);
 
780
 
 
781
  uint32_t server_capabilites;
 
782
  {
 
783
    /* buff[] needs to big enough to hold the server_version variable */
 
784
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
 
785
 
 
786
    server_capabilites= CLIENT_BASIC_FLAGS;
 
787
 
 
788
#ifdef HAVE_COMPRESS
 
789
    server_capabilites|= CLIENT_COMPRESS;
 
790
#endif /* HAVE_COMPRESS */
 
791
 
 
792
    end= buff + strlen(server_version);
 
793
    if ((end - buff) >= SERVER_VERSION_LENGTH)
 
794
      end= buff + (SERVER_VERSION_LENGTH - 1);
 
795
    memcpy(buff, server_version, end - buff);
 
796
    *end= 0;
 
797
    end++;
 
798
 
 
799
    int4store((unsigned char*) end, thread_id);
 
800
    end+= 4;
 
801
    /*
 
802
      So as _checkConnection is the only entry point to authorization
 
803
      procedure, scramble is set here. This gives us new scramble for
 
804
      each handshake.
 
805
    */
 
806
    drizzleclient_create_random_string(scramble, SCRAMBLE_LENGTH, &rand);
 
807
    /*
 
808
      Old clients does not understand long scrambles, but can ignore packet
 
809
      tail: that's why first part of the scramble is placed here, and second
 
810
      part at the end of packet.
 
811
    */
 
812
    end= strncpy(end, scramble, SCRAMBLE_LENGTH_323);
 
813
    end+= SCRAMBLE_LENGTH_323;
 
814
 
 
815
    *end++= 0; /* an empty byte for some reason */
 
816
 
 
817
    int2store(end, server_capabilites);
 
818
    /* write server characteristics: up to 16 bytes allowed */
 
819
    end[2]=(char) default_charset_info->number;
 
820
    int2store(end+3, session->server_status);
 
821
    memset(end+5, 0, 13);
 
822
    end+= 18;
 
823
    /* write scramble tail */
 
824
    size_t scramble_len= SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323;
 
825
    end= strncpy(end, scramble + SCRAMBLE_LENGTH_323, scramble_len);
 
826
    end+= scramble_len;
 
827
 
 
828
    *end++= 0; /* an empty byte for some reason */
 
829
 
 
830
    /* At this point we write connection message and read reply */
 
831
    if (drizzleclient_net_write_command(&net
 
832
          , (unsigned char) protocol_version
 
833
          , (unsigned char*) ""
 
834
          , 0
 
835
          , (unsigned char*) buff
 
836
          , (size_t) (end-buff)) 
 
837
        ||    (pkt_len= drizzleclient_net_read(&net)) == packet_error 
 
838
        || pkt_len < MIN_HANDSHAKE_SIZE)
 
839
    {
 
840
      my_error(ER_HANDSHAKE_ERROR, MYF(0), session->security_ctx.ip.c_str());
 
841
      return false;
 
842
    }
 
843
  }
 
844
  if (session->packet.alloc(session->variables.net_buffer_length))
 
845
    return false; /* The error is set by alloc(). */
 
846
 
 
847
  session->client_capabilities= uint2korr(net.read_pos);
 
848
 
 
849
 
 
850
  session->client_capabilities|= ((uint32_t) uint2korr(net.read_pos + 2)) << 16;
 
851
  session->max_client_packet_length= uint4korr(net.read_pos + 4);
 
852
  session->update_charset();
 
853
  end= (char*) net.read_pos + 32;
 
854
 
 
855
  /*
 
856
    Disable those bits which are not supported by the server.
 
857
    This is a precautionary measure, if the client lies. See Bug#27944.
 
858
  */
 
859
  session->client_capabilities&= server_capabilites;
 
860
 
 
861
  if (end >= (char*) net.read_pos + pkt_len + 2)
 
862
  {
 
863
    my_error(ER_HANDSHAKE_ERROR, MYF(0), session->security_ctx.ip.c_str());
 
864
    return false;
 
865
  }
 
866
 
 
867
  net.return_status= &session->server_status;
 
868
 
 
869
  char *user= end;
 
870
  char *passwd= strchr(user, '\0')+1;
 
871
  uint32_t user_len= passwd - user - 1;
 
872
  char *l_db= passwd;
 
873
  char db_buff[NAME_LEN + 1];           // buffer to store db in utf8
 
874
  char user_buff[USERNAME_LENGTH + 1];    // buffer to store user in utf8
 
875
  uint32_t dummy_errors;
 
876
 
 
877
  /*
 
878
    Old clients send null-terminated string as password; new clients send
 
879
    the size (1 byte) + string (not null-terminated). Hence in case of empty
 
880
    password both send '\0'.
 
881
 
 
882
    This strlen() can't be easily deleted without changing protocol.
 
883
 
 
884
    Cast *passwd to an unsigned char, so that it doesn't extend the sign for
 
885
    *passwd > 127 and become 2**32-127+ after casting to uint.
 
886
  */
 
887
  uint32_t passwd_len= session->client_capabilities & CLIENT_SECURE_CONNECTION ?
 
888
    (unsigned char)(*passwd++) : strlen(passwd);
 
889
  l_db= session->client_capabilities & CLIENT_CONNECT_WITH_DB ? l_db + passwd_len + 1 : 0;
 
890
 
 
891
  /* strlen() can't be easily deleted without changing protocol */
 
892
  uint32_t db_len= l_db ? strlen(l_db) : 0;
 
893
 
 
894
  if (passwd + passwd_len + db_len > (char *) net.read_pos + pkt_len)
 
895
  {
 
896
    my_error(ER_HANDSHAKE_ERROR, MYF(0), session->security_ctx.ip.c_str());
 
897
    return false;
 
898
  }
 
899
 
 
900
  /* Since 4.1 all database names are stored in utf8 */
 
901
  if (l_db)
 
902
  {
 
903
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
 
904
                             system_charset_info,
 
905
                             l_db, db_len,
 
906
                             session->charset(), &dummy_errors)]= 0;
 
907
    l_db= db_buff;
 
908
  }
 
909
 
 
910
  user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
 
911
                                       system_charset_info, user, user_len,
 
912
                                       session->charset(), &dummy_errors)]= '\0';
 
913
  user= user_buff;
 
914
 
 
915
  /* If username starts and ends in "'", chop them off */
 
916
  if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
 
917
  {
 
918
    user[user_len-1]= 0;
 
919
    user++;
 
920
    user_len-= 2;
 
921
  }
 
922
 
 
923
  session->security_ctx.user.assign(user);
 
924
 
 
925
  return session->checkUser(passwd, passwd_len, l_db);
 
926
}
 
927
 
 
928
static ProtocolFactoryOldLibdrizzle *factory= NULL;
 
929
 
 
930
static int init(PluginRegistry &registry)
 
931
{
 
932
  factory= new ProtocolFactoryOldLibdrizzle;
 
933
  registry.add(factory); 
 
934
  return 0;
 
935
}
 
936
 
 
937
static int deinit(PluginRegistry &registry)
 
938
{
 
939
  if (factory)
 
940
  {
 
941
    registry.remove(factory);
 
942
    delete factory;
 
943
  }
 
944
  return 0;
 
945
}
 
946
 
 
947
drizzle_declare_plugin(oldlibdrizzle)
 
948
{
 
949
  "oldlibdrizzle",
 
950
  "0.1",
 
951
  "Eric Day",
 
952
  "Old libdrizzle Protocol",
 
953
  PLUGIN_LICENSE_GPL,
 
954
  init,   /* Plugin Init */
 
955
  deinit, /* Plugin Deinit */
 
956
  NULL,   /* status variables */
 
957
  NULL,   /* system variables */
 
958
  NULL    /* config options */
 
959
}
 
960
drizzle_declare_plugin_end;