~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/oldlibdrizzle/oldlibdrizzle.cc

  • Committer: Brian Aker
  • Date: 2009-10-15 00:22:33 UTC
  • mto: (1183.1.11 merge)
  • mto: This revision was merged to the branch mainline in revision 1198.
  • Revision ID: brian@gaz-20091015002233-fa4ao2mbc67wls91
First pass of information engine. OMG, ponies... is it so much easier to
deal with creating and engine.

The list table iterator though... its ass, needs to go. We should also
abstract out share. Very few engines need a custom one. Just say'in

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"
 
20
#include <drizzled/server_includes.h>
23
21
#include <drizzled/gettext.h>
24
22
#include <drizzled/error.h>
25
23
#include <drizzled/query_id.h>
26
24
#include <drizzled/sql_state.h>
27
25
#include <drizzled/session.h>
28
 
#include "drizzled/internal/my_sys.h"
29
 
#include "drizzled/internal/m_string.h"
30
26
#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;
 
27
 
 
28
#include "pack.h"
 
29
#include "errmsg.h"
 
30
#include "oldlibdrizzle.h"
 
31
#include "options.h"
 
32
 
 
33
using namespace std;
39
34
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)
 
35
 
 
36
#define PROTOCOL_VERSION 10
 
37
 
 
38
extern uint32_t drizzled_tcp_port;
 
39
 
 
40
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
 
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
static uint32_t buffer_length;
 
46
static char* bind_address;
 
47
 
 
48
const char* ListenOldLibdrizzle::getHost(void) const
 
49
{
 
50
  return bind_address;
 
51
}
 
52
 
 
53
in_port_t ListenOldLibdrizzle::getPort(void) const
 
54
{
 
55
  return (in_port_t) drizzled_tcp_port;
 
56
}
 
57
 
 
58
plugin::Client *ListenOldLibdrizzle::getClient(int fd)
87
59
{
88
60
  int new_fd;
89
61
  new_fd= acceptTcp(fd);
90
62
  if (new_fd == -1)
91
63
    return NULL;
92
64
 
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);
 
65
  return new (nothrow) ClientOldLibdrizzle(new_fd);
 
66
}
 
67
 
 
68
ClientOldLibdrizzle::ClientOldLibdrizzle(int fd)
 
69
{
 
70
  net.vio= 0;
 
71
 
 
72
  if (fd == -1)
 
73
    return;
 
74
 
 
75
  if (drizzleclient_net_init_sock(&net, fd, 0, buffer_length))
 
76
    throw bad_alloc();
 
77
 
 
78
  drizzleclient_net_set_read_timeout(&net, read_timeout);
 
79
  drizzleclient_net_set_write_timeout(&net, write_timeout);
 
80
  net.retry_count=retry_count;
 
81
}
 
82
 
 
83
ClientOldLibdrizzle::~ClientOldLibdrizzle()
 
84
{
 
85
  if (net.vio)
 
86
    drizzleclient_vio_close(net.vio);
 
87
}
 
88
 
 
89
int ClientOldLibdrizzle::getFileDescriptor(void)
 
90
{
 
91
  return drizzleclient_net_get_sd(&net);
 
92
}
 
93
 
 
94
bool ClientOldLibdrizzle::isConnected()
 
95
{
 
96
  return net.vio != 0;
 
97
}
 
98
 
 
99
bool ClientOldLibdrizzle::isReading(void)
 
100
{
 
101
  return net.reading_or_writing == 1;
 
102
}
 
103
 
 
104
bool ClientOldLibdrizzle::isWriting(void)
 
105
{
 
106
  return net.reading_or_writing == 2;
 
107
}
 
108
 
 
109
bool ClientOldLibdrizzle::flush()
 
110
{
 
111
  if (net.vio == NULL)
 
112
    return false;
 
113
  bool ret= drizzleclient_net_write(&net, (unsigned char*) packet.ptr(),
 
114
                           packet.length());
 
115
  packet.length(0);
 
116
  return ret;
 
117
}
 
118
 
 
119
void ClientOldLibdrizzle::close(void)
 
120
{
 
121
  if (net.vio)
 
122
  { 
 
123
    drizzleclient_net_close(&net);
 
124
    drizzleclient_net_end(&net);
 
125
  }
 
126
}
 
127
 
 
128
bool ClientOldLibdrizzle::authenticate()
 
129
{
 
130
  bool connection_is_valid;
 
131
 
 
132
  /* Use "connect_timeout" value during connection phase */
 
133
  drizzleclient_net_set_read_timeout(&net, connect_timeout);
 
134
  drizzleclient_net_set_write_timeout(&net, connect_timeout);
 
135
 
 
136
  connection_is_valid= checkConnection();
 
137
 
 
138
  if (connection_is_valid)
 
139
    sendOK();
 
140
  else
 
141
  {
 
142
    sendError(session->main_da.sql_errno(), session->main_da.message());
 
143
    return false;
 
144
  }
 
145
 
 
146
  /* Connect completed, set read/write timeouts back to default */
 
147
  drizzleclient_net_set_read_timeout(&net, read_timeout);
 
148
  drizzleclient_net_set_write_timeout(&net, write_timeout);
 
149
  return true;
 
150
}
 
151
 
 
152
bool ClientOldLibdrizzle::readCommand(char **l_packet, uint32_t *packet_length)
 
153
{
 
154
  /*
 
155
    This thread will do a blocking read from the client which
 
156
    will be interrupted when the next command is received from
 
157
    the client, the connection is closed or "net_wait_timeout"
 
158
    number of seconds has passed
 
159
  */
 
160
#ifdef NEVER
 
161
  /* We can do this much more efficiently with poll timeouts or watcher thread,
 
162
     disabling for now, which means net_wait_timeout == read_timeout. */
 
163
  drizzleclient_net_set_read_timeout(&net,
 
164
                                     session->variables.net_wait_timeout);
 
165
#endif
 
166
 
 
167
  net.pkt_nr=0;
 
168
 
 
169
  *packet_length= drizzleclient_net_read(&net);
 
170
  if (*packet_length == packet_error)
 
171
  {
 
172
    /* Check if we can continue without closing the connection */
 
173
 
 
174
    if(net.last_errno== CR_NET_PACKET_TOO_LARGE)
 
175
      my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
 
176
    if (session->main_da.status() == Diagnostics_area::DA_ERROR)
 
177
      sendError(session->main_da.sql_errno(), session->main_da.message());
 
178
    else
 
179
      sendOK();
 
180
 
 
181
    if (net.error != 3)
 
182
      return false;                       // We have to close it.
 
183
 
 
184
    net.error= 0;
 
185
    *packet_length= 0;
 
186
    return true;
 
187
  }
 
188
 
 
189
  *l_packet= (char*) net.read_pos;
 
190
 
 
191
  /*
 
192
    'packet_length' contains length of data, as it was stored in packet
 
193
    header. In case of malformed header, drizzleclient_net_read returns zero.
 
194
    If packet_length is not zero, drizzleclient_net_read ensures that the returned
 
195
    number of bytes was actually read from network.
 
196
    There is also an extra safety measure in drizzleclient_net_read:
 
197
    it sets packet[packet_length]= 0, but only for non-zero packets.
 
198
  */
 
199
 
 
200
  if (*packet_length == 0)                       /* safety */
 
201
  {
 
202
    /* Initialize with COM_SLEEP packet */
 
203
    (*l_packet)[0]= (unsigned char) COM_SLEEP;
 
204
    *packet_length= 1;
 
205
  }
 
206
  /* Do not rely on drizzleclient_net_read, extra safety against programming errors. */
 
207
  (*l_packet)[*packet_length]= '\0';                  /* safety */
 
208
 
 
209
#ifdef NEVER
 
210
  /* See comment above. */
 
211
  /* Restore read timeout value */
 
212
  drizzleclient_net_set_read_timeout(&net,
 
213
                                     session->variables.net_read_timeout);
 
214
#endif
 
215
 
 
216
  return true;
 
217
}
 
218
 
 
219
/**
 
220
  Return ok to the client.
 
221
 
 
222
  The ok packet has the following structure:
 
223
 
 
224
  - 0               : Marker (1 byte)
 
225
  - affected_rows    : Stored in 1-9 bytes
 
226
  - id        : Stored in 1-9 bytes
 
227
  - server_status    : Copy of session->server_status;  Can be used by client
 
228
  to check if we are inside an transaction.
 
229
  New in 4.0 client
 
230
  - warning_count    : Stored in 2 bytes; New in 4.1 client
 
231
  - message        : Stored as packed length (1-9 bytes) + message.
 
232
  Is not stored if no message.
 
233
 
 
234
  @param session           Thread handler
 
235
  @param affected_rows       Number of rows changed by statement
 
236
  @param id           Auto_increment id for first row (if used)
 
237
  @param message       Message to send to the client (Used by mysql_status)
 
238
*/
 
239
 
 
240
void ClientOldLibdrizzle::sendOK()
 
241
{
 
242
  unsigned char buff[DRIZZLE_ERRMSG_SIZE+10],*pos;
 
243
  const char *message= NULL;
 
244
  uint32_t tmp;
 
245
 
 
246
  if (!net.vio)    // hack for re-parsing queries
 
247
  {
 
248
    return;
 
249
  }
 
250
 
 
251
  buff[0]=0;                    // No fields
 
252
  if (session->main_da.status() == Diagnostics_area::DA_OK)
 
253
  {
 
254
    if (client_capabilities & CLIENT_FOUND_ROWS && session->main_da.found_rows())
 
255
      pos=drizzleclient_net_store_length(buff+1,session->main_da.found_rows());
 
256
    else
 
257
      pos=drizzleclient_net_store_length(buff+1,session->main_da.affected_rows());
 
258
    pos=drizzleclient_net_store_length(pos, session->main_da.last_insert_id());
 
259
    int2store(pos, session->main_da.server_status());
 
260
    pos+=2;
 
261
    tmp= min(session->main_da.total_warn_count(), (uint32_t)65535);
 
262
    message= session->main_da.message();
 
263
  }
 
264
  else
 
265
  {
 
266
    pos=drizzleclient_net_store_length(buff+1,0);
 
267
    pos=drizzleclient_net_store_length(pos, 0);
 
268
    int2store(pos, session->server_status);
 
269
    pos+=2;
 
270
    tmp= min(session->total_warn_count, (uint32_t)65535);
 
271
  }
 
272
 
 
273
  /* We can only return up to 65535 warnings in two bytes */
 
274
  int2store(pos, tmp);
 
275
  pos+= 2;
 
276
 
 
277
  session->main_da.can_overwrite_status= true;
 
278
 
 
279
  if (message && message[0])
 
280
  {
 
281
    size_t length= strlen(message);
 
282
    pos=drizzleclient_net_store_length(pos,length);
 
283
    memcpy(pos,(unsigned char*) message,length);
 
284
    pos+=length;
 
285
  }
 
286
  drizzleclient_net_write(&net, buff, (size_t) (pos-buff));
 
287
  drizzleclient_net_flush(&net);
 
288
 
 
289
  session->main_da.can_overwrite_status= false;
 
290
}
 
291
 
 
292
/**
 
293
  Send eof (= end of result set) to the client.
 
294
 
 
295
  The eof packet has the following structure:
 
296
 
 
297
  - 254    (DRIZZLE_PROTOCOL_NO_MORE_DATA)    : Marker (1 byte)
 
298
  - warning_count    : Stored in 2 bytes; New in 4.1 client
 
299
  - status_flag    : Stored in 2 bytes;
 
300
  For flags like SERVER_MORE_RESULTS_EXISTS.
 
301
 
 
302
  Note that the warning count will not be sent if 'no_flush' is set as
 
303
  we don't want to report the warning count until all data is sent to the
 
304
  client.
 
305
*/
 
306
 
 
307
void ClientOldLibdrizzle::sendEOF()
 
308
{
 
309
  /* Set to true if no active vio, to work well in case of --init-file */
 
310
  if (net.vio != 0)
 
311
  {
 
312
    session->main_da.can_overwrite_status= true;
 
313
    writeEOFPacket(session->main_da.server_status(),
 
314
                   session->main_da.total_warn_count());
 
315
    drizzleclient_net_flush(&net);
 
316
    session->main_da.can_overwrite_status= false;
 
317
  }
 
318
  packet.shrink(buffer_length);
 
319
}
 
320
 
 
321
 
 
322
void ClientOldLibdrizzle::sendError(uint32_t sql_errno, const char *err)
 
323
{
 
324
  uint32_t length;
 
325
  /*
 
326
    buff[]: sql_errno:2 + ('#':1 + SQLSTATE_LENGTH:5) + DRIZZLE_ERRMSG_SIZE:512
 
327
  */
 
328
  unsigned char buff[2+1+SQLSTATE_LENGTH+DRIZZLE_ERRMSG_SIZE], *pos;
 
329
 
 
330
  assert(sql_errno);
 
331
  assert(err && err[0]);
 
332
 
 
333
  /*
 
334
    It's one case when we can push an error even though there
 
335
    is an OK or EOF already.
 
336
  */
 
337
  session->main_da.can_overwrite_status= true;
 
338
 
 
339
  /* Abort multi-result sets */
 
340
  session->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
 
341
 
 
342
  /**
 
343
    Send a error string to client.
 
344
 
 
345
    For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
 
346
    critical that every error that can be intercepted is issued in one
 
347
    place only, my_message_sql.
 
348
  */
 
349
 
 
350
  if (net.vio == 0)
 
351
  {
 
352
    return;
 
353
  }
 
354
 
 
355
  int2store(buff,sql_errno);
 
356
  pos= buff+2;
 
357
 
 
358
  /* The first # is to make the client backward compatible */
 
359
  buff[2]= '#';
 
360
  pos= (unsigned char*) strcpy((char*) buff+3, drizzle_errno_to_sqlstate(sql_errno));
 
361
  pos+= strlen(drizzle_errno_to_sqlstate(sql_errno));
 
362
 
 
363
  char *tmp= strncpy((char*)pos, err, DRIZZLE_ERRMSG_SIZE-1);
 
364
  tmp+= strlen((char*)pos);
 
365
  tmp[0]= '\0';
 
366
  length= (uint32_t)(tmp-(char*)buff);
 
367
  err= (char*) buff;
 
368
 
 
369
  drizzleclient_net_write_command(&net,(unsigned char) 255, (unsigned char*) "", 0, (unsigned char*) err, length);
 
370
 
 
371
  session->main_da.can_overwrite_status= false;
 
372
}
 
373
 
 
374
/**
 
375
  Send name and type of result to client.
 
376
 
 
377
  Sum fields has table name empty and field_name.
 
378
 
 
379
  @param Session        Thread data object
 
380
  @param list            List of items to send to client
 
381
  @param flag            Bit mask with the following functions:
 
382
                        - 1 send number of rows
 
383
                        - 2 send default values
 
384
                        - 4 don't write eof packet
 
385
 
 
386
  @retval
 
387
    0    ok
 
388
  @retval
 
389
    1    Error  (Note that in this case the error is not sent to the
 
390
    client)
 
391
*/
 
392
bool ClientOldLibdrizzle::sendFields(List<Item> *list)
 
393
{
 
394
  List_iterator_fast<Item> it(*list);
 
395
  Item *item;
 
396
  unsigned char buff[80];
 
397
  String tmp((char*) buff,sizeof(buff),&my_charset_bin);
 
398
 
 
399
  unsigned char *row_pos= drizzleclient_net_store_length(buff, list->elements);
 
400
  (void) drizzleclient_net_write(&net, buff, (size_t) (row_pos-buff));
 
401
 
 
402
  while ((item=it++))
 
403
  {
 
404
    char *pos;
 
405
    SendField field;
 
406
    item->make_field(&field);
 
407
 
 
408
    packet.length(0);
 
409
 
 
410
    if (store(STRING_WITH_LEN("def")) ||
 
411
        store(field.db_name) ||
 
412
        store(field.table_name) ||
 
413
        store(field.org_table_name) ||
 
414
        store(field.col_name) ||
 
415
        store(field.org_col_name) ||
 
416
        packet.realloc(packet.length()+12))
 
417
      goto err;
 
418
 
 
419
    /* Store fixed length fields */
 
420
    pos= (char*) packet.ptr()+packet.length();
 
421
    *pos++= 12;                // Length of packed fields
 
422
    /* No conversion */
 
423
    int2store(pos, field.charsetnr);
 
424
    int4store(pos+2, field.length);
 
425
    pos[6]= field.type;
 
426
    int2store(pos+7,field.flags);
 
427
    pos[9]= (char) field.decimals;
 
428
    pos[10]= 0;                // For the future
 
429
    pos[11]= 0;                // For the future
 
430
    pos+= 12;
 
431
 
 
432
    packet.length((uint32_t) (pos - packet.ptr()));
 
433
    if (flush())
 
434
      break;
 
435
  }
 
436
 
 
437
  /*
 
438
    Mark the end of meta-data result set, and store session->server_status,
 
439
    to show that there is no cursor.
 
440
    Send no warning information, as it will be sent at statement end.
 
441
  */
 
442
  writeEOFPacket(session->server_status, session->total_warn_count);
 
443
  return 0;
 
444
 
 
445
err:
 
446
  my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
 
447
             MYF(0));
 
448
  return 1;
 
449
}
 
450
 
 
451
bool ClientOldLibdrizzle::store(Field *from)
 
452
{
 
453
  if (from->is_null())
 
454
    return store();
 
455
  char buff[MAX_FIELD_WIDTH];
 
456
  String str(buff,sizeof(buff), &my_charset_bin);
 
457
 
 
458
  from->val_str(&str);
 
459
 
 
460
  return netStoreData((const unsigned char *)str.ptr(), str.length());
 
461
}
 
462
 
 
463
bool ClientOldLibdrizzle::store(void)
 
464
{
 
465
  char buff[1];
 
466
  buff[0]= (char)251;
 
467
  return packet.append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
 
468
}
 
469
 
 
470
bool ClientOldLibdrizzle::store(int32_t from)
 
471
{
 
472
  char buff[12];
 
473
  return netStoreData((unsigned char*) buff,
 
474
                      (size_t) (int10_to_str(from, buff, -10) - buff));
 
475
}
 
476
 
 
477
bool ClientOldLibdrizzle::store(uint32_t from)
 
478
{
 
479
  char buff[11];
 
480
  return netStoreData((unsigned char*) buff,
 
481
                      (size_t) (int10_to_str(from, buff, 10) - buff));
 
482
}
 
483
 
 
484
bool ClientOldLibdrizzle::store(int64_t from)
 
485
{
 
486
  char buff[22];
 
487
  return netStoreData((unsigned char*) buff,
 
488
                      (size_t) (int64_t10_to_str(from, buff, -10) - buff));
 
489
}
 
490
 
 
491
bool ClientOldLibdrizzle::store(uint64_t from)
 
492
{
 
493
  char buff[21];
 
494
  return netStoreData((unsigned char*) buff,
 
495
                      (size_t) (int64_t10_to_str(from, buff, 10) - buff));
 
496
}
 
497
 
 
498
bool ClientOldLibdrizzle::store(double from, uint32_t decimals, String *buffer)
 
499
{
 
500
  buffer->set_real(from, decimals, session->charset());
 
501
  return netStoreData((unsigned char*) buffer->ptr(), buffer->length());
 
502
}
 
503
 
 
504
bool ClientOldLibdrizzle::store(const char *from, size_t length)
 
505
{
 
506
  return netStoreData((const unsigned char *)from, length);
 
507
}
 
508
 
 
509
bool ClientOldLibdrizzle::wasAborted(void)
 
510
{
 
511
  return net.error && net.vio != 0;
 
512
}
 
513
 
 
514
bool ClientOldLibdrizzle::haveMoreData(void)
 
515
{
 
516
  return drizzleclient_net_more_data(&net);
 
517
}
 
518
 
 
519
bool ClientOldLibdrizzle::haveError(void)
 
520
{
 
521
  return net.error || net.vio == 0;
 
522
}
 
523
 
 
524
bool ClientOldLibdrizzle::checkConnection(void)
 
525
{
 
526
  uint32_t pkt_len= 0;
 
527
  char *end;
 
528
 
 
529
  // TCP/IP connection
 
530
  {
 
531
    char ip[NI_MAXHOST];
 
532
    uint16_t port;
 
533
 
 
534
    if (drizzleclient_net_peer_addr(&net, ip, &port, NI_MAXHOST))
 
535
    {
 
536
      my_error(ER_BAD_HOST_ERROR, MYF(0), session->security_ctx.ip.c_str());
 
537
      return false;
 
538
    }
 
539
 
 
540
    session->security_ctx.ip.assign(ip);
 
541
  }
 
542
  drizzleclient_net_keepalive(&net, true);
 
543
 
 
544
  uint32_t server_capabilites;
 
545
  {
 
546
    /* buff[] needs to big enough to hold the server_version variable */
 
547
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
 
548
 
 
549
    server_capabilites= CLIENT_BASIC_FLAGS;
 
550
 
 
551
#ifdef HAVE_COMPRESS
 
552
    server_capabilites|= CLIENT_COMPRESS;
 
553
#endif /* HAVE_COMPRESS */
 
554
 
 
555
    end= buff + strlen(VERSION);
 
556
    if ((end - buff) >= SERVER_VERSION_LENGTH)
 
557
      end= buff + (SERVER_VERSION_LENGTH - 1);
 
558
    memcpy(buff, VERSION, end - buff);
 
559
    *end= 0;
 
560
    end++;
 
561
 
 
562
    int4store((unsigned char*) end, global_thread_id);
 
563
    end+= 4;
 
564
 
 
565
    /* We don't use scramble anymore. */
 
566
    memset(end, 'X', SCRAMBLE_LENGTH_323);
 
567
    end+= SCRAMBLE_LENGTH_323;
 
568
    *end++= 0; /* an empty byte for some reason */
 
569
 
 
570
    int2store(end, server_capabilites);
 
571
    /* write server characteristics: up to 16 bytes allowed */
 
572
    end[2]=(char) default_charset_info->number;
 
573
    int2store(end+3, session->server_status);
 
574
    memset(end+5, 0, 13);
 
575
    end+= 18;
 
576
 
 
577
    /* Write scramble tail. */
 
578
    memset(end, 'X', SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
 
579
    end+= (SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
 
580
    *end++= 0; /* an empty byte for some reason */
 
581
 
 
582
    /* At this point we write connection message and read reply */
 
583
    if (drizzleclient_net_write_command(&net
 
584
          , (unsigned char) PROTOCOL_VERSION
 
585
          , (unsigned char*) ""
 
586
          , 0
 
587
          , (unsigned char*) buff
 
588
          , (size_t) (end-buff)) 
 
589
        ||    (pkt_len= drizzleclient_net_read(&net)) == packet_error 
 
590
        || pkt_len < MIN_HANDSHAKE_SIZE)
 
591
    {
 
592
      my_error(ER_HANDSHAKE_ERROR, MYF(0), session->security_ctx.ip.c_str());
 
593
      return false;
 
594
    }
 
595
  }
 
596
  if (packet.alloc(buffer_length))
 
597
    return false; /* The error is set by alloc(). */
 
598
 
 
599
  client_capabilities= uint2korr(net.read_pos);
 
600
 
 
601
 
 
602
  client_capabilities|= ((uint32_t) uint2korr(net.read_pos + 2)) << 16;
 
603
  session->max_client_packet_length= uint4korr(net.read_pos + 4);
 
604
  end= (char*) net.read_pos + 32;
 
605
 
 
606
  /*
 
607
    Disable those bits which are not supported by the server.
 
608
    This is a precautionary measure, if the client lies. See Bug#27944.
 
609
  */
 
610
  client_capabilities&= server_capabilites;
 
611
 
 
612
  if (end >= (char*) net.read_pos + pkt_len + 2)
 
613
  {
 
614
    my_error(ER_HANDSHAKE_ERROR, MYF(0), session->security_ctx.ip.c_str());
 
615
    return false;
 
616
  }
 
617
 
 
618
  net.return_status= &session->server_status;
 
619
 
 
620
  char *user= end;
 
621
  char *passwd= strchr(user, '\0')+1;
 
622
  uint32_t user_len= passwd - user - 1;
 
623
  char *l_db= passwd;
 
624
 
 
625
  /*
 
626
    Old clients send null-terminated string as password; new clients send
 
627
    the size (1 byte) + string (not null-terminated). Hence in case of empty
 
628
    password both send '\0'.
 
629
 
 
630
    This strlen() can't be easily deleted without changing client.
 
631
 
 
632
    Cast *passwd to an unsigned char, so that it doesn't extend the sign for
 
633
    *passwd > 127 and become 2**32-127+ after casting to uint.
 
634
  */
 
635
  uint32_t passwd_len= client_capabilities & CLIENT_SECURE_CONNECTION ?
 
636
    (unsigned char)(*passwd++) : strlen(passwd);
 
637
  l_db= client_capabilities & CLIENT_CONNECT_WITH_DB ? l_db + passwd_len + 1 : 0;
 
638
 
 
639
  /* strlen() can't be easily deleted without changing client */
 
640
  uint32_t db_len= l_db ? strlen(l_db) : 0;
 
641
 
 
642
  if (passwd + passwd_len + db_len > (char *) net.read_pos + pkt_len)
 
643
  {
 
644
    my_error(ER_HANDSHAKE_ERROR, MYF(0), session->security_ctx.ip.c_str());
 
645
    return false;
 
646
  }
 
647
 
 
648
  /* If username starts and ends in "'", chop them off */
 
649
  if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
 
650
  {
 
651
    user[user_len-1]= 0;
 
652
    user++;
 
653
    user_len-= 2;
 
654
  }
 
655
 
 
656
  session->security_ctx.user.assign(user);
 
657
 
 
658
  return session->checkUser(passwd, passwd_len, l_db);
 
659
}
 
660
 
 
661
bool ClientOldLibdrizzle::netStoreData(const unsigned char *from, size_t length)
 
662
{
 
663
  size_t packet_length= packet.length();
 
664
  /*
 
665
     The +9 comes from that strings of length longer than 16M require
 
666
     9 bytes to be stored (see drizzleclient_net_store_length).
 
667
  */
 
668
  if (packet_length+9+length > packet.alloced_length() &&
 
669
      packet.realloc(packet_length+9+length))
 
670
    return 1;
 
671
  unsigned char *to= drizzleclient_net_store_length((unsigned char*) packet.ptr()+packet_length, length);
 
672
  memcpy(to,from,length);
 
673
  packet.length((size_t) (to+length-(unsigned char*) packet.ptr()));
 
674
  return 0;
 
675
}
 
676
 
 
677
/**
 
678
  Format EOF packet according to the current client and
 
679
  write it to the network output buffer.
 
680
*/
 
681
 
 
682
void ClientOldLibdrizzle::writeEOFPacket(uint32_t server_status,
 
683
                                         uint32_t total_warn_count)
 
684
{
 
685
  unsigned char buff[5];
 
686
  /*
 
687
    Don't send warn count during SP execution, as the warn_list
 
688
    is cleared between substatements, and mysqltest gets confused
 
689
  */
 
690
  uint32_t tmp= min(total_warn_count, (uint32_t)65535);
 
691
  buff[0]= DRIZZLE_PROTOCOL_NO_MORE_DATA;
 
692
  int2store(buff+1, tmp);
 
693
  /*
 
694
    The following test should never be true, but it's better to do it
 
695
    because if 'is_fatal_error' is set the server is not going to execute
 
696
    other queries (see the if test in dispatch_command / COM_QUERY)
 
697
  */
 
698
  if (session->is_fatal_error)
 
699
    server_status&= ~SERVER_MORE_RESULTS_EXISTS;
 
700
  int2store(buff + 3, server_status);
 
701
  drizzleclient_net_write(&net, buff, 5);
 
702
}
 
703
 
 
704
static ListenOldLibdrizzle *listen_obj= NULL;
 
705
 
 
706
static int init(drizzled::plugin::Registry &registry)
 
707
{
 
708
  listen_obj= new ListenOldLibdrizzle("oldlibdrizzle");
 
709
  registry.add(listen_obj); 
 
710
  return 0;
 
711
}
 
712
 
 
713
static int deinit(drizzled::plugin::Registry &registry)
 
714
{
 
715
  registry.remove(listen_obj);
 
716
  delete listen_obj;
 
717
  return 0;
 
718
}
 
719
 
 
720
static DRIZZLE_SYSVAR_UINT(connect_timeout, connect_timeout,
 
721
                           PLUGIN_VAR_RQCMDARG, N_("Connect Timeout."),
 
722
                           NULL, NULL, 10, 1, 300, 0);
 
723
static DRIZZLE_SYSVAR_UINT(read_timeout, read_timeout, PLUGIN_VAR_RQCMDARG,
 
724
                           N_("Read Timeout."), NULL, NULL, 30, 1, 300, 0);
 
725
static DRIZZLE_SYSVAR_UINT(write_timeout, write_timeout, PLUGIN_VAR_RQCMDARG,
 
726
                           N_("Write Timeout."), NULL, NULL, 60, 1, 300, 0);
 
727
static DRIZZLE_SYSVAR_UINT(retry_count, retry_count, PLUGIN_VAR_RQCMDARG,
 
728
                           N_("Retry Count."), NULL, NULL, 10, 1, 100, 0);
 
729
static DRIZZLE_SYSVAR_UINT(buffer_length, buffer_length, PLUGIN_VAR_RQCMDARG,
 
730
                           N_("Buffer length."), NULL, NULL, 16384, 1024,
 
731
                           1024*1024, 0);
 
732
static DRIZZLE_SYSVAR_STR(bind_address, bind_address, PLUGIN_VAR_READONLY,
 
733
                          N_("Address to bind to."), NULL, NULL, NULL);
 
734
 
 
735
static struct st_mysql_sys_var* system_variables[]= {
 
736
  DRIZZLE_SYSVAR(connect_timeout),
 
737
  DRIZZLE_SYSVAR(read_timeout),
 
738
  DRIZZLE_SYSVAR(write_timeout),
 
739
  DRIZZLE_SYSVAR(retry_count),
 
740
  DRIZZLE_SYSVAR(buffer_length),
 
741
  DRIZZLE_SYSVAR(bind_address),
 
742
  NULL
 
743
};
 
744
 
 
745
drizzle_declare_plugin(oldlibdrizzle)
 
746
{
 
747
  "oldlibdrizzle",
 
748
  "0.1",
 
749
  "Eric Day",
 
750
  "Old libdrizzle Client",
 
751
  PLUGIN_LICENSE_GPL,
 
752
  init,             /* Plugin Init */
 
753
  deinit,           /* Plugin Deinit */
 
754
  NULL,             /* status variables */
 
755
  system_variables, /* system variables */
 
756
  NULL              /* config options */
 
757
}
 
758
drizzle_declare_plugin_end;