~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/mysql_protocol/mysql_protocol.cc

  • Committer: Olaf van der Spek
  • Date: 2011-03-29 12:04:36 UTC
  • mto: (2257.1.1 build) (2276.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 2258.
  • Revision ID: olafvdspek@gmail.com-20110329120436-vozkuer8vqgh027p
Always call assert()

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
18
 */
19
19
 
20
 
#include "config.h"
 
20
#include <config.h>
21
21
#include <drizzled/gettext.h>
22
22
#include <drizzled/error.h>
23
23
#include <drizzled/query_id.h>
24
 
#include <drizzled/sql_state.h>
 
24
#include <drizzled/error/sql_state.h>
25
25
#include <drizzled/session.h>
26
 
#include "drizzled/internal/m_string.h"
 
26
#include <drizzled/internal/m_string.h>
27
27
#include <algorithm>
28
28
#include <boost/program_options.hpp>
29
29
#include <drizzled/module/option_map.h>
30
 
#include "drizzled/util/tokenize.h"
 
30
#include <drizzled/util/tokenize.h>
31
31
#include "errmsg.h"
32
32
#include "mysql_protocol.h"
33
33
#include "mysql_password.h"
34
34
#include "options.h"
35
 
#include "table_function.h"
36
 
 
37
 
#include "drizzled/identifier.h"
38
 
 
 
35
#include <drizzled/identifier.h>
 
36
#include <drizzled/plugin/function.h>
 
37
#include <drizzled/diagnostics_area.h>
 
38
#include <drizzled/system_variables.h>
 
39
#include <libdrizzle/constants.h>
 
40
 
 
41
#define MIN_HANDSHAKE_SIZE 6
39
42
#define PROTOCOL_VERSION 10
40
43
 
41
44
namespace po= boost::program_options;
66
69
ListenMySQLProtocol::~ListenMySQLProtocol()
67
70
{ }
68
71
 
 
72
void ListenMySQLProtocol::addCountersToTable()
 
73
{
 
74
  counters.push_back(new drizzled::plugin::ListenCounter(new std::string("connection_count"), &getCounters()->connectionCount));
 
75
  counters.push_back(new drizzled::plugin::ListenCounter(new std::string("connected"), &getCounters()->connected));
 
76
  counters.push_back(new drizzled::plugin::ListenCounter(new std::string("failed_connections"), &getCounters()->failedConnections));
 
77
}
 
78
 
69
79
const std::string ListenMySQLProtocol::getHost(void) const
70
80
{
71
81
  return _hostname;
89
99
ClientMySQLProtocol::ClientMySQLProtocol(int fd, bool using_mysql41_protocol, ProtocolCounters *set_counters):
90
100
  is_admin_connection(false),
91
101
  _using_mysql41_protocol(using_mysql41_protocol),
 
102
  _is_interactive(false),
92
103
  counters(set_counters)
93
104
{
94
105
  
148
159
    drizzleclient_net_close(&net);
149
160
    drizzleclient_net_end(&net);
150
161
    if (is_admin_connection)
 
162
    {
151
163
      counters->adminConnected.decrement();
 
164
    }
152
165
    else
 
166
    {
153
167
      counters->connected.decrement();
 
168
    }
154
169
  }
155
170
}
156
171
 
189
204
  }
190
205
  else
191
206
  {
192
 
    sendError(session->main_da.sql_errno(), session->main_da.message());
 
207
    sendError(session->main_da().sql_errno(), session->main_da().message());
193
208
    counters->failedConnections.increment();
194
209
    return false;
195
210
  }
224
239
 
225
240
    if(net.last_errno== ER_NET_PACKET_TOO_LARGE)
226
241
      my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
227
 
    if (session->main_da.status() == Diagnostics_area::DA_ERROR)
228
 
      sendError(session->main_da.sql_errno(), session->main_da.message());
 
242
    if (session->main_da().status() == Diagnostics_area::DA_ERROR)
 
243
      sendError(session->main_da().sql_errno(), session->main_da().message());
229
244
    else
230
245
      sendOK();
231
246
 
267
282
      (*l_packet)[0]= (unsigned char) COM_SHUTDOWN;
268
283
      break;
269
284
 
 
285
    case 12: /* KILL */
 
286
      (*l_packet)[0]= (unsigned char) COM_KILL;
 
287
      break;
 
288
 
270
289
    case 14: /* PING */
271
290
      (*l_packet)[0]= (unsigned char) COM_PING;
272
291
      break;
326
345
  }
327
346
 
328
347
  buff[0]=0;                    // No fields
329
 
  if (session->main_da.status() == Diagnostics_area::DA_OK)
 
348
  if (session->main_da().status() == Diagnostics_area::DA_OK)
330
349
  {
331
 
    if (client_capabilities & CLIENT_FOUND_ROWS && session->main_da.found_rows())
332
 
      pos=storeLength(buff+1,session->main_da.found_rows());
 
350
    if (client_capabilities & CLIENT_FOUND_ROWS && session->main_da().found_rows())
 
351
      pos=storeLength(buff+1,session->main_da().found_rows());
333
352
    else
334
 
      pos=storeLength(buff+1,session->main_da.affected_rows());
335
 
    pos=storeLength(pos, session->main_da.last_insert_id());
336
 
    int2store(pos, session->main_da.server_status());
 
353
      pos=storeLength(buff+1,session->main_da().affected_rows());
 
354
    pos=storeLength(pos, session->main_da().last_insert_id());
 
355
    int2store(pos, session->main_da().server_status());
337
356
    pos+=2;
338
 
    tmp= min(session->main_da.total_warn_count(), (uint32_t)65535);
339
 
    message= session->main_da.message();
 
357
    tmp= min(session->main_da().total_warn_count(), (uint32_t)65535);
 
358
    message= session->main_da().message();
340
359
  }
341
360
  else
342
361
  {
351
370
  int2store(pos, tmp);
352
371
  pos+= 2;
353
372
 
354
 
  session->main_da.can_overwrite_status= true;
 
373
  session->main_da().can_overwrite_status= true;
355
374
 
356
375
  if (message && message[0])
357
376
  {
363
382
  drizzleclient_net_write(&net, buff, (size_t) (pos-buff));
364
383
  drizzleclient_net_flush(&net);
365
384
 
366
 
  session->main_da.can_overwrite_status= false;
 
385
  session->main_da().can_overwrite_status= false;
367
386
}
368
387
 
369
388
/**
386
405
  /* Set to true if no active vio, to work well in case of --init-file */
387
406
  if (net.vio != 0)
388
407
  {
389
 
    session->main_da.can_overwrite_status= true;
390
 
    writeEOFPacket(session->main_da.server_status(),
391
 
                   session->main_da.total_warn_count());
 
408
    session->main_da().can_overwrite_status= true;
 
409
    writeEOFPacket(session->main_da().server_status(),
 
410
                   session->main_da().total_warn_count());
392
411
    drizzleclient_net_flush(&net);
393
 
    session->main_da.can_overwrite_status= false;
 
412
    session->main_da().can_overwrite_status= false;
394
413
  }
395
414
  packet.shrink(buffer_length.get());
396
415
}
397
416
 
398
417
 
399
 
void ClientMySQLProtocol::sendError(uint32_t sql_errno, const char *err)
 
418
void ClientMySQLProtocol::sendError(drizzled::error_t sql_errno, const char *err)
400
419
{
401
420
  uint32_t length;
402
421
  /*
404
423
  */
405
424
  unsigned char buff[2+1+SQLSTATE_LENGTH+DRIZZLE_ERRMSG_SIZE], *pos;
406
425
 
407
 
  assert(sql_errno);
 
426
  assert(sql_errno != EE_OK);
408
427
  assert(err && err[0]);
409
428
 
410
429
  /*
411
430
    It's one case when we can push an error even though there
412
431
    is an OK or EOF already.
413
432
  */
414
 
  session->main_da.can_overwrite_status= true;
 
433
  session->main_da().can_overwrite_status= true;
415
434
 
416
435
  /* Abort multi-result sets */
417
436
  session->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
429
448
    return;
430
449
  }
431
450
 
432
 
  int2store(buff,sql_errno);
 
451
  int2store(buff, static_cast<uint16_t>(sql_errno));
433
452
  pos= buff+2;
434
453
 
435
454
  /* The first # is to make the client backward compatible */
436
455
  buff[2]= '#';
437
 
  pos= (unsigned char*) strcpy((char*) buff+3, drizzle_errno_to_sqlstate(sql_errno));
438
 
  pos+= strlen(drizzle_errno_to_sqlstate(sql_errno));
 
456
  pos= (unsigned char*) strcpy((char*) buff+3, error::convert_to_sqlstate(sql_errno));
 
457
  pos+= strlen(error::convert_to_sqlstate(sql_errno));
439
458
 
440
459
  char *tmp= strncpy((char*)pos, err, DRIZZLE_ERRMSG_SIZE-1);
441
460
  tmp+= strlen((char*)pos);
447
466
 
448
467
  drizzleclient_net_flush(&net);
449
468
 
450
 
  session->main_da.can_overwrite_status= false;
 
469
  session->main_da().can_overwrite_status= false;
451
470
}
452
471
 
453
472
/**
470
489
*/
471
490
bool ClientMySQLProtocol::sendFields(List<Item> *list)
472
491
{
473
 
  List_iterator_fast<Item> it(*list);
 
492
  List<Item>::iterator it(list->begin());
474
493
  Item *item;
475
494
  unsigned char buff[80];
476
495
  String tmp((char*) buff,sizeof(buff),&my_charset_bin);
477
496
 
478
 
  unsigned char *row_pos= storeLength(buff, list->elements);
 
497
  unsigned char *row_pos= storeLength(buff, list->size());
479
498
  (void) drizzleclient_net_write(&net, buff, (size_t) (row_pos-buff));
480
499
 
481
500
  while ((item=it++))
508
527
      switch (field.type)
509
528
      {
510
529
      case DRIZZLE_TYPE_LONG:
511
 
        pos[6]= 3;
 
530
        pos[6]= DRIZZLE_COLUMN_TYPE_LONG;
512
531
        break;
513
532
 
514
533
      case DRIZZLE_TYPE_DOUBLE:
515
 
        pos[6]= 5;
 
534
        pos[6]= DRIZZLE_COLUMN_TYPE_DOUBLE;
516
535
        break;
517
536
 
518
537
      case DRIZZLE_TYPE_NULL:
519
 
        pos[6]= 6;
 
538
        pos[6]= DRIZZLE_COLUMN_TYPE_NULL;
520
539
        break;
521
540
 
522
541
      case DRIZZLE_TYPE_TIMESTAMP:
523
 
        pos[6]= 7;
 
542
        pos[6]= DRIZZLE_COLUMN_TYPE_TIMESTAMP;
524
543
        break;
525
544
 
526
545
      case DRIZZLE_TYPE_LONGLONG:
527
 
        pos[6]= 8;
 
546
        pos[6]= DRIZZLE_COLUMN_TYPE_LONGLONG;
528
547
        break;
529
548
 
530
549
      case DRIZZLE_TYPE_DATETIME:
531
 
        pos[6]= 12;
 
550
        pos[6]= DRIZZLE_COLUMN_TYPE_DATETIME;
 
551
        break;
 
552
 
 
553
      case DRIZZLE_TYPE_TIME:
 
554
        pos[6]= DRIZZLE_COLUMN_TYPE_TIME;
532
555
        break;
533
556
 
534
557
      case DRIZZLE_TYPE_DATE:
535
 
        pos[6]= 14;
 
558
        pos[6]= DRIZZLE_COLUMN_TYPE_DATE;
536
559
        break;
537
560
 
538
561
      case DRIZZLE_TYPE_VARCHAR:
539
 
        pos[6]= 15;
 
562
        pos[6]= DRIZZLE_COLUMN_TYPE_VARCHAR;
 
563
        break;
 
564
 
 
565
      case DRIZZLE_TYPE_MICROTIME:
 
566
        pos[6]= DRIZZLE_COLUMN_TYPE_VARCHAR;
540
567
        break;
541
568
 
542
569
      case DRIZZLE_TYPE_UUID:
543
 
        pos[6]= 15;
 
570
        pos[6]= DRIZZLE_COLUMN_TYPE_VARCHAR;
 
571
        break;
 
572
 
 
573
      case DRIZZLE_TYPE_BOOLEAN:
 
574
        pos[6]= DRIZZLE_COLUMN_TYPE_TINY;
544
575
        break;
545
576
 
546
577
      case DRIZZLE_TYPE_DECIMAL:
547
 
        pos[6]= (char)246;
 
578
        pos[6]= (char)DRIZZLE_COLUMN_TYPE_NEWDECIMAL;
548
579
        break;
549
580
 
550
581
      case DRIZZLE_TYPE_ENUM:
551
 
        pos[6]= (char)247;
 
582
        pos[6]= (char)DRIZZLE_COLUMN_TYPE_ENUM;
552
583
        break;
553
584
 
554
585
      case DRIZZLE_TYPE_BLOB:
555
 
        pos[6]= (char)252;
 
586
        pos[6]= (char)DRIZZLE_COLUMN_TYPE_BLOB;
556
587
        break;
557
588
      }
558
589
    }
591
622
{
592
623
  if (from->is_null())
593
624
    return store();
 
625
  if (from->type() == DRIZZLE_TYPE_BOOLEAN)
 
626
  {
 
627
    return store(from->val_int());
 
628
  }
 
629
 
594
630
  char buff[MAX_FIELD_WIDTH];
595
631
  String str(buff,sizeof(buff), &my_charset_bin);
596
632
 
665
701
  uint32_t pkt_len= 0;
666
702
  char *end;
667
703
  char scramble[SCRAMBLE_LENGTH];
668
 
  identifier::User::shared_ptr user_identifier= identifier::User::make_shared();
 
704
  identifier::user::mptr user_identifier= identifier::User::make_shared();
669
705
 
670
706
  makeScramble(scramble);
671
707
 
692
728
    server_capabilites= CLIENT_BASIC_FLAGS;
693
729
 
694
730
    if (_using_mysql41_protocol)
 
731
    {
695
732
      server_capabilites|= CLIENT_PROTOCOL_MYSQL41;
 
733
    }
696
734
 
697
735
#ifdef HAVE_COMPRESS
698
736
    server_capabilites|= CLIENT_COMPRESS;
783
821
      passwd < (char *) net.read_pos + pkt_len)
784
822
  {
785
823
    passwd_len= (unsigned char)(*passwd++);
786
 
    if (passwd_len > 0)
 
824
    if (passwd_len > 0 and client_capabilities & CLIENT_CAPABILITIES_PLUGIN_AUTH)
 
825
    {
 
826
      user_identifier->setPasswordType(identifier::User::PLAIN_TEXT);
 
827
    }
 
828
    else if (passwd_len > 0)
787
829
    {
788
830
      user_identifier->setPasswordType(identifier::User::MYSQL_HASH);
789
831
      user_identifier->setPasswordContext(scramble, SCRAMBLE_LENGTH);
834
876
    }
835
877
  }
836
878
 
 
879
  if (client_capabilities & CLIENT_INTERACTIVE)
 
880
  {
 
881
    _is_interactive= true;
 
882
  }
 
883
 
 
884
  if (client_capabilities & CLIENT_CAPABILITIES_PLUGIN_AUTH)
 
885
  {
 
886
    passwd_len= strlen(passwd);
 
887
  }
 
888
 
837
889
  user_identifier->setUser(user);
838
890
  session->setUser(user_identifier);
839
891
 
967
1019
 
968
1020
static int init(drizzled::module::Context &context)
969
1021
{  
970
 
  context.add(new MysqlProtocolStatus);
971
 
 
972
1022
  /* Initialize random seeds for the MySQL algorithm with minimal changes. */
973
1023
  time_t seed_time= time(NULL);
974
1024
  random_seed1= seed_time % random_max;
980
1030
  context.add(mysql_password);
981
1031
 
982
1032
  listen_obj= new ListenMySQLProtocol("mysql_protocol", vm["bind-address"].as<std::string>(), true);
 
1033
  listen_obj->addCountersToTable();
983
1034
  context.add(listen_obj); 
984
1035
  context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", port));
985
1036
  context.registerVariable(new sys_var_constrained_value<uint32_t>("connect_timeout", connect_timeout));
999
1050
{
1000
1051
  context("port",
1001
1052
          po::value<port_constraint>(&port)->default_value(3306),
1002
 
          N_("Port number to use for connection or 0 for default to with MySQL "
 
1053
          _("Port number to use for connection or 0 for default to with MySQL "
1003
1054
                              "protocol."));
1004
1055
  context("connect-timeout",
1005
1056
          po::value<timeout_constraint>(&connect_timeout)->default_value(10),
1006
 
          N_("Connect Timeout."));
 
1057
          _("Connect Timeout."));
1007
1058
  context("read-timeout",
1008
1059
          po::value<timeout_constraint>(&read_timeout)->default_value(30),
1009
 
          N_("Read Timeout."));
 
1060
          _("Read Timeout."));
1010
1061
  context("write-timeout",
1011
1062
          po::value<timeout_constraint>(&write_timeout)->default_value(60),
1012
 
          N_("Write Timeout."));
 
1063
          _("Write Timeout."));
1013
1064
  context("retry-count",
1014
1065
          po::value<retry_constraint>(&retry_count)->default_value(10),
1015
 
          N_("Retry Count."));
 
1066
          _("Retry Count."));
1016
1067
  context("buffer-length",
1017
1068
          po::value<buffer_constraint>(&buffer_length)->default_value(16384),
1018
 
          N_("Buffer length."));
 
1069
          _("Buffer length."));
1019
1070
  context("bind-address",
1020
 
          po::value<string>()->default_value(""),
1021
 
          N_("Address to bind to."));
 
1071
          po::value<string>()->default_value("localhost"),
 
1072
          _("Address to bind to."));
1022
1073
  context("max-connections",
1023
1074
          po::value<uint32_t>(&ListenMySQLProtocol::mysql_counters->max_connections)->default_value(1000),
1024
 
          N_("Maximum simultaneous connections."));
 
1075
          _("Maximum simultaneous connections."));
1025
1076
  context("admin-ip-addresses",
1026
1077
          po::value<vector<string> >()->composing()->notifier(&ClientMySQLProtocol::mysql_compose_ip_addresses),
1027
 
          N_("A restrictive IP address list for incoming admin connections."));
1028
 
}
1029
 
 
1030
 
static int mysql_protocol_connection_count_func(drizzle_show_var *var, char *buff)
1031
 
{
1032
 
  var->type= SHOW_LONGLONG;
1033
 
  var->value= buff;
1034
 
  *((uint64_t *)buff)= ListenMySQLProtocol::mysql_counters->connectionCount;
1035
 
  return 0;
1036
 
}
1037
 
 
1038
 
static int mysql_protocol_connected_count_func(drizzle_show_var *var, char *buff)
1039
 
{
1040
 
  var->type= SHOW_LONGLONG;
1041
 
  var->value= buff;
1042
 
  *((uint64_t *)buff)= ListenMySQLProtocol::mysql_counters->connected;
1043
 
  return 0;
1044
 
}
1045
 
 
1046
 
static int mysql_protocol_failed_count_func(drizzle_show_var *var, char *buff)
1047
 
{
1048
 
  var->type= SHOW_LONGLONG;
1049
 
  var->value= buff;
1050
 
  *((uint64_t *)buff)= ListenMySQLProtocol::mysql_counters->failedConnections;
1051
 
  return 0;
1052
 
}
1053
 
 
1054
 
static st_show_var_func_container mysql_protocol_connection_count=
1055
 
  { &mysql_protocol_connection_count_func };
1056
 
 
1057
 
static st_show_var_func_container mysql_protocol_connected_count=
1058
 
  { &mysql_protocol_connected_count_func };
1059
 
 
1060
 
static st_show_var_func_container mysql_protocol_failed_count=
1061
 
  { &mysql_protocol_failed_count_func };
1062
 
 
1063
 
static drizzle_show_var mysql_protocol_status_variables[]= {
1064
 
  {"Connections",
1065
 
  (char*) &mysql_protocol_connection_count, SHOW_FUNC},
1066
 
  {"Connected",
1067
 
  (char*) &mysql_protocol_connected_count, SHOW_FUNC},
1068
 
  {"Failed_connections",
1069
 
  (char*) &mysql_protocol_failed_count, SHOW_FUNC},
1070
 
  {NULL, NULL, SHOW_LONGLONG}
1071
 
};
1072
 
 
1073
 
MysqlProtocolStatus::Generator::Generator(drizzled::Field **fields) :
1074
 
  plugin::TableFunction::Generator(fields)
1075
 
{
1076
 
  status_var_ptr= mysql_protocol_status_variables;
1077
 
}
1078
 
 
1079
 
bool MysqlProtocolStatus::Generator::populate()
1080
 
{
1081
 
  MY_ALIGNED_BYTE_ARRAY(buff_data, SHOW_VAR_FUNC_BUFF_SIZE, int64_t);
1082
 
  char * const buff= (char *) &buff_data;
1083
 
  drizzle_show_var tmp;
1084
 
 
1085
 
  if (status_var_ptr->name)
1086
 
  {
1087
 
    std::ostringstream oss;
1088
 
    string return_value;
1089
 
    const char *value;
1090
 
    int type;
1091
 
 
1092
 
    push(status_var_ptr->name);
1093
 
 
1094
 
    if (status_var_ptr->type == SHOW_FUNC)
1095
 
    {
1096
 
      ((drizzle_show_var_func)((st_show_var_func_container *)status_var_ptr->value)->func)(&tmp, buff);
1097
 
      value= buff;
1098
 
      type= tmp.type;
1099
 
    }
1100
 
    else
1101
 
    {
1102
 
      value= status_var_ptr->value;
1103
 
      type= status_var_ptr->type;
1104
 
    }
1105
 
 
1106
 
    switch(type)
1107
 
    {
1108
 
    case SHOW_LONGLONG:
1109
 
      oss << *(uint64_t*) value;
1110
 
      return_value= oss.str();
1111
 
      break;
1112
 
    default:
1113
 
      assert(0);
1114
 
    }
1115
 
    if (return_value.length())
1116
 
      push(return_value);
1117
 
    else
1118
 
      push(" ");
1119
 
 
1120
 
    status_var_ptr++;
1121
 
 
1122
 
    return true;
1123
 
  }
1124
 
  return false;
 
1078
          _("A restrictive IP address list for incoming admin connections."));
1125
1079
}
1126
1080
 
1127
1081
} /* namespace drizzle_plugin */
1135
1089
  "MySQL Protocol Module",
1136
1090
  PLUGIN_LICENSE_GPL,
1137
1091
  drizzle_plugin::init,             /* Plugin Init */
1138
 
  NULL, /* system variables */
 
1092
  NULL, /* depends */
1139
1093
  drizzle_plugin::init_options    /* config options */
1140
1094
}
1141
1095
DRIZZLE_DECLARE_PLUGIN_END;