Class: Mysql2::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/mysql2/client.rb,
ext/mysql2/client.c

Direct Known Subclasses

EM::Client

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Client

Returns a new instance of Client.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/mysql2/client.rb', line 21

def initialize(opts = {})
  fail Mysql2::Error, "Options parameter must be a Hash" unless opts.is_a? Hash
  opts = Mysql2::Util.key_hash_as_symbols(opts)
  @read_timeout = nil
  @query_options = self.class.default_query_options.dup
  @query_options.merge! opts

  initialize_ext

  # Set default connect_timeout to avoid unlimited retries from signal interruption
  opts[:connect_timeout] = 120 unless opts.key?(:connect_timeout)

  # TODO: stricter validation rather than silent massaging
  [:reconnect, :connect_timeout, :local_infile, :read_timeout, :write_timeout, :default_file, :default_group, :secure_auth, :init_command, :automatic_close].each do |key|
    next unless opts.key?(key)
    case key
    when :reconnect, :local_infile, :secure_auth, :automatic_close
      send(:"#{key}=", !!opts[key]) # rubocop:disable Style/DoubleNegation
    when :connect_timeout, :read_timeout, :write_timeout
      send(:"#{key}=", Integer(opts[key])) unless opts[key].nil?
    else
      send(:"#{key}=", opts[key])
    end
  end

  # force the encoding to utf8
  self.charset_name = opts[:encoding] || 'utf8'

  ssl_options = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher)
  ssl_set(*ssl_options) if ssl_options.any?
  self.ssl_mode = parse_ssl_mode(opts[:ssl_mode]) if opts[:ssl_mode]

  case opts[:flags]
  when Array
    flags = parse_flags_array(opts[:flags], @query_options[:connect_flags])
  when String
    flags = parse_flags_array(opts[:flags].split(' '), @query_options[:connect_flags])
  when Integer
    flags = @query_options[:connect_flags] | opts[:flags]
  else
    flags = @query_options[:connect_flags]
  end

  # SSL verify is a connection flag rather than a mysql_ssl_set option
  flags |= SSL_VERIFY_SERVER_CERT if opts[:sslverify] && ssl_options.any?

  if [:user, :pass, :hostname, :dbname, :db, :sock].any? { |k| @query_options.key?(k) }
    warn "============= WARNING FROM mysql2 ============="
    warn "The options :user, :pass, :hostname, :dbname, :db, and :sock will be deprecated at some point in the future."
    warn "Instead, please use :username, :password, :host, :port, :database, :socket, :flags for the options."
    warn "============= END WARNING FROM mysql2 ========="
  end

  user     = opts[:username] || opts[:user]
  pass     = opts[:password] || opts[:pass]
  host     = opts[:host] || opts[:hostname]
  port     = opts[:port]
  database = opts[:database] || opts[:dbname] || opts[:db]
  socket   = opts[:socket] || opts[:sock]

  # Correct the data types before passing these values down to the C level
  user = user.to_s unless user.nil?
  pass = pass.to_s unless pass.nil?
  host = host.to_s unless host.nil?
  port = port.to_i unless port.nil?
  database = database.to_s unless database.nil?
  socket = socket.to_s unless socket.nil?

  connect user, pass, host, port, database, socket, flags
end

Instance Attribute Details

#query_optionsObject (readonly)

Returns the value of attribute query_options.



3
4
5
# File 'lib/mysql2/client.rb', line 3

def query_options
  @query_options
end

#read_timeoutObject (readonly)

Returns the value of attribute read_timeout.



3
4
5
# File 'lib/mysql2/client.rb', line 3

def read_timeout
  @read_timeout
end

Class Method Details

.default_query_optionsObject



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/mysql2/client.rb', line 5

def self.default_query_options
  @default_query_options ||= {
    :as => :hash,                   # the type of object you want each row back as; also supports :array (an array of values)
    :async => false,                # don't wait for a result after sending the query, you'll have to monitor the socket yourself then eventually call Mysql2::Client#async_result
    :cast_booleans => false,        # cast tinyint(1) fields as true/false in ruby
    :symbolize_keys => false,       # return field names as symbols instead of strings
    :database_timezone => :local,   # timezone Mysql2 will assume datetime objects are stored in
    :application_timezone => nil,   # timezone Mysql2 will convert to before handing the object back to the caller
    :cache_rows => true,            # tells Mysql2 to use its internal row cache for results
    :connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION,
    :cast => true,
    :default_file => nil,
    :default_group => nil,
  }
end

.Mysql2::Client.escape(string) ⇒ Object

Escape string so that it may be used in a SQL statement. Note that this escape method is not connection encoding aware. If you need encoding support use Mysql2::Client#escape instead.



335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'ext/mysql2/client.c', line 335

static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
  unsigned char *newStr;
  VALUE rb_str;
  unsigned long newLen, oldLen;

  Check_Type(str, T_STRING);

  oldLen = RSTRING_LEN(str);
  newStr = xmalloc(oldLen*2+1);

  newLen = mysql_escape_string((char *)newStr, RSTRING_PTR(str), oldLen);
  if (newLen == oldLen) {
    /* no need to return a new ruby string if nothing changed */
    xfree(newStr);
    return str;
  } else {
    rb_str = rb_str_new((const char*)newStr, newLen);
#ifdef HAVE_RUBY_ENCODING_H
    rb_enc_copy(rb_str, str);
#endif
    xfree(newStr);
    return rb_str;
  }
}

.infoObject

Returns a string that represents the client library version.



918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
# File 'ext/mysql2/client.c', line 918

static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE klass) {
  VALUE version_info, version, header_version;
  version_info = rb_hash_new();

  version = rb_str_new2(mysql_get_client_info());
  header_version = rb_str_new2(MYSQL_LINK_VERSION);

#ifdef HAVE_RUBY_ENCODING_H
  rb_enc_associate(version, rb_usascii_encoding());
  rb_enc_associate(header_version, rb_usascii_encoding());
#endif

  rb_hash_aset(version_info, sym_id, LONG2NUM(mysql_get_client_version()));
  rb_hash_aset(version_info, sym_version, version);
  rb_hash_aset(version_info, sym_header_version, header_version);

  return version_info;
}

Instance Method Details

#abandon_results!Object

When using MULTI_STATEMENTS support, calling this will throw away any unprocessed results as fast as it can in order to put the connection back into a state where queries can be issued again.



703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
# File 'ext/mysql2/client.c', line 703

static VALUE rb_mysql_client_abandon_results(VALUE self) {
  MYSQL_RES *result;
  int ret;

  GET_CLIENT(self);

  while (mysql_more_results(wrapper->client) == 1) {
    ret = mysql_next_result(wrapper->client);
    if (ret > 0) {
      rb_raise_mysql2_error(wrapper);
    }

    result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);

    if (result != NULL) {
      mysql_free_result(result);
    }
  }

  return Qnil;
}

#affected_rowsObject

returns the number of rows changed, deleted, or inserted by the last statement if it was an UPDATE, DELETE, or INSERT.



1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
# File 'ext/mysql2/client.c', line 1004

static VALUE rb_mysql_client_affected_rows(VALUE self) {
  my_ulonglong retVal;
  GET_CLIENT(self);

  REQUIRE_CONNECTED(wrapper);
  retVal = mysql_affected_rows(wrapper->client);
  if (retVal == (my_ulonglong)-1) {
    rb_raise_mysql2_error(wrapper);
  }
  return ULL2NUM(retVal);
}

#async_resultObject

Returns the result for the last async issued query.



543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
# File 'ext/mysql2/client.c', line 543

static VALUE rb_mysql_client_async_result(VALUE self) {
  MYSQL_RES * result;
  VALUE resultObj;
  VALUE current, is_streaming;
  GET_CLIENT(self);

  /* if we're not waiting on a result, do nothing */
  if (NIL_P(wrapper->active_thread))
    return Qnil;

  REQUIRE_CONNECTED(wrapper);
  if ((VALUE)rb_thread_call_without_gvl(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
    /* an error occurred, mark this connection inactive */
    wrapper->active_thread = Qnil;
    rb_raise_mysql2_error(wrapper);
  }

  is_streaming = rb_hash_aref(rb_iv_get(self, "@current_query_options"), sym_stream);
  if (is_streaming == Qtrue) {
    result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_use_result, wrapper, RUBY_UBF_IO, 0);
  } else {
    result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
  }

  if (result == NULL) {
    if (mysql_errno(wrapper->client) != 0) {
      wrapper->active_thread = Qnil;
      rb_raise_mysql2_error(wrapper);
    }
    /* no data and no error, so query was not a SELECT */
    return Qnil;
  }

  current = rb_hash_dup(rb_iv_get(self, "@current_query_options"));
  (void)RB_GC_GUARD(current);
  Check_Type(current, T_HASH);
  resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);

  return resultObj;
}

#automatic_close=(false) ⇒ Object

Set this to false to leave the connection open after it is garbage collected. To avoid “Aborted connection” errors on the server, explicitly call close when the connection is no longer needed.



1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
# File 'ext/mysql2/client.c', line 1182

static VALUE set_automatic_close(VALUE self, VALUE value) {
  GET_CLIENT(self);
  if (RTEST(value)) {
    wrapper->automatic_close = 1;
  } else {
#ifndef _WIN32
    wrapper->automatic_close = 0;
#else
    rb_warn("Connections are always closed by garbage collector on Windows");
#endif
  }
  return value;
}

#automatic_close?Boolean

Returns:

  • (Boolean)


1168
1169
1170
1171
# File 'ext/mysql2/client.c', line 1168

static VALUE get_automatic_close(VALUE self) {
  GET_CLIENT(self);
  return wrapper->automatic_close ? Qtrue : Qfalse;
}

#closenil

Immediately disconnect from the server; normally the garbage collector will disconnect automatically when a connection is no longer needed. Explicitly closing this will free up server resources sooner than waiting for the garbage collector.

Returns:

  • (nil)


465
466
467
468
469
470
471
472
473
# File 'ext/mysql2/client.c', line 465

static VALUE rb_mysql_client_close(VALUE self) {
  GET_CLIENT(self);

  if (wrapper->connected) {
    rb_thread_call_without_gvl(nogvl_close, wrapper, RUBY_UBF_IO, 0);
  }

  return Qnil;
}

#encodingObject

Returns the encoding set on the client.



1157
1158
1159
1160
# File 'ext/mysql2/client.c', line 1157

static VALUE rb_mysql_client_encoding(VALUE self) {
  GET_CLIENT(self);
  return wrapper->encoding;
}

#escape(string) ⇒ Object

Escape string so that it may be used in a SQL statement.



784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
# File 'ext/mysql2/client.c', line 784

static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
  unsigned char *newStr;
  VALUE rb_str;
  unsigned long newLen, oldLen;
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *default_internal_enc;
  rb_encoding *conn_enc;
#endif
  GET_CLIENT(self);

  REQUIRE_CONNECTED(wrapper);
  Check_Type(str, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
  default_internal_enc = rb_default_internal_encoding();
  conn_enc = rb_to_encoding(wrapper->encoding);
  /* ensure the string is in the encoding the connection is expecting */
  str = rb_str_export_to_enc(str, conn_enc);
#endif

  oldLen = RSTRING_LEN(str);
  newStr = xmalloc(oldLen*2+1);

  newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, RSTRING_PTR(str), oldLen);
  if (newLen == oldLen) {
    /* no need to return a new ruby string if nothing changed */
#ifdef HAVE_RUBY_ENCODING_H
    if (default_internal_enc) {
      str = rb_str_export_to_enc(str, default_internal_enc);
    }
#endif
    xfree(newStr);
    return str;
  } else {
    rb_str = rb_str_new((const char*)newStr, newLen);
#ifdef HAVE_RUBY_ENCODING_H
    rb_enc_associate(rb_str, conn_enc);
    if (default_internal_enc) {
      rb_str = rb_str_export_to_enc(rb_str, default_internal_enc);
    }
#endif
    xfree(newStr);
    return rb_str;
  }
}

#infoObject



137
138
139
# File 'lib/mysql2/client.rb', line 137

def info
  self.class.info
end

#last_idObject

Returns the value generated for an AUTO_INCREMENT column by the previous INSERT or UPDATE statement.



992
993
994
995
996
# File 'ext/mysql2/client.c', line 992

static VALUE rb_mysql_client_last_id(VALUE self) {
  GET_CLIENT(self);
  REQUIRE_CONNECTED(wrapper);
  return ULL2NUM(mysql_insert_id(wrapper->client));
}

#more_results?Boolean

Returns true or false if there are more results to process.

Returns:

  • (Boolean)


1090
1091
1092
1093
1094
1095
1096
1097
# File 'ext/mysql2/client.c', line 1090

static VALUE rb_mysql_client_more_results(VALUE self)
{
  GET_CLIENT(self);
  if (mysql_more_results(wrapper->client) == 0)
    return Qfalse;
  else
    return Qtrue;
}

#next_resultObject

Fetch the next result set from the server. Returns nothing.



1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
# File 'ext/mysql2/client.c', line 1105

static VALUE rb_mysql_client_next_result(VALUE self)
{
    int ret;
    GET_CLIENT(self);
    ret = mysql_next_result(wrapper->client);
    if (ret > 0) {
      rb_raise_mysql2_error(wrapper);
      return Qfalse;
    } else if (ret == 0) {
      return Qtrue;
    } else {
      return Qfalse;
    }
}

#parse_flags_array(flags, initial = 0) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/mysql2/client.rb', line 103

def parse_flags_array(flags, initial = 0)
  flags.reduce(initial) do |memo, f|
    fneg = f.start_with?('-') ? f[1..-1] : nil
    if fneg && fneg =~ /^\w+$/ && Mysql2::Client.const_defined?(fneg)
      memo & ~ Mysql2::Client.const_get(fneg)
    elsif f && f =~ /^\w+$/ && Mysql2::Client.const_defined?(f)
      memo | Mysql2::Client.const_get(f)
    else
      warn "Unknown MySQL connection flag: '#{f}'"
      memo
    end
  end
end

#parse_ssl_mode(mode) ⇒ Object



92
93
94
95
96
97
98
99
100
101
# File 'lib/mysql2/client.rb', line 92

def parse_ssl_mode(mode)
  m = mode.to_s.upcase
  if m.start_with?('SSL_MODE_')
    return Mysql2::Client.const_get(m) if Mysql2::Client.const_defined?(m)
  else
    x = 'SSL_MODE_' + m
    return Mysql2::Client.const_get(x) if Mysql2::Client.const_defined?(x)
  end
  warn "Unknown MySQL ssl_mode flag: #{mode}"
end

#pingObject

Checks whether the connection to the server is working. If the connection has gone down and auto-reconnect is enabled an attempt to reconnect is made. If the connection is down and auto-reconnect is disabled, ping returns an error.



1075
1076
1077
1078
1079
1080
1081
1082
1083
# File 'ext/mysql2/client.c', line 1075

static VALUE rb_mysql_client_ping(VALUE self) {
  GET_CLIENT(self);

  if (!wrapper->connected) {
    return Qfalse;
  } else {
    return (VALUE)rb_thread_call_without_gvl(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
  }
}

#prepare(sql) ⇒ Object

Create a new prepared statement.



1322
1323
1324
1325
1326
1327
# File 'ext/mysql2/client.c', line 1322

static VALUE rb_mysql_client_prepare_statement(VALUE self, VALUE sql) {
  GET_CLIENT(self);
  REQUIRE_CONNECTED(wrapper);

  return rb_mysql_stmt_new(self, sql);
}

#query(sql, options = {}) ⇒ Object



118
119
120
121
122
# File 'lib/mysql2/client.rb', line 118

def query(sql, options = {})
  Thread.handle_interrupt(::Mysql2::Util::TimeoutError => :never) do
    _query(sql, @query_options.merge(options))
  end
end

#query_infoObject



129
130
131
132
133
134
135
# File 'lib/mysql2/client.rb', line 129

def query_info
  info = query_info_string
  return {} unless info
  info_hash = {}
  info.split.each_slice(2) { |s| info_hash[s[0].downcase.delete(':').to_sym] = s[1].to_i }
  info_hash
end

#query_info_stringObject



369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# File 'ext/mysql2/client.c', line 369

static VALUE rb_mysql_info(VALUE self) {
  const char *info;
  VALUE rb_str;
  GET_CLIENT(self);

  info = mysql_info(wrapper->client);

  if (info == NULL) {
    return Qnil;
  }

  rb_str = rb_str_new2(info);
#ifdef HAVE_RUBY_ENCODING_H
  rb_enc_associate(rb_str, rb_utf8_encoding());
#endif

  return rb_str;
}

#reconnect=(true) ⇒ Object

Enable or disable the automatic reconnect behavior of libmysql. Read dev.mysql.com/doc/refman/5.5/en/auto-reconnect.html for more information.



1203
1204
1205
# File 'ext/mysql2/client.c', line 1203

static VALUE set_reconnect(VALUE self, VALUE value) {
  return _mysql_client_options(self, MYSQL_OPT_RECONNECT, value);
}

#select_db(name) ⇒ Object

Causes the database specified by name to become the default (current) database on the connection specified by mysql.



1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
# File 'ext/mysql2/client.c', line 1045

static VALUE rb_mysql_client_select_db(VALUE self, VALUE db)
{
  struct nogvl_select_db_args args;

  GET_CLIENT(self);
  REQUIRE_CONNECTED(wrapper);

  args.mysql = wrapper->client;
  args.db = StringValueCStr(db);

  if (rb_thread_call_without_gvl(nogvl_select_db, &args, RUBY_UBF_IO, 0) == Qfalse)
    rb_raise_mysql2_error(wrapper);

  return db;
}

#server_infoObject

Returns a string that represents the server version number



942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
# File 'ext/mysql2/client.c', line 942

static VALUE rb_mysql_client_server_info(VALUE self) {
  VALUE version, server_info;
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *default_internal_enc;
  rb_encoding *conn_enc;
#endif
  GET_CLIENT(self);

  REQUIRE_CONNECTED(wrapper);
#ifdef HAVE_RUBY_ENCODING_H
  default_internal_enc = rb_default_internal_encoding();
  conn_enc = rb_to_encoding(wrapper->encoding);
#endif

  version = rb_hash_new();
  rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
  server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
#ifdef HAVE_RUBY_ENCODING_H
  rb_enc_associate(server_info, conn_enc);
  if (default_internal_enc) {
    server_info = rb_str_export_to_enc(server_info, default_internal_enc);
  }
#endif
  rb_hash_aset(version, sym_version, server_info);
  return version;
}

#socketObject



981
982
983
# File 'ext/mysql2/client.c', line 981

static VALUE rb_mysql_client_socket(RB_MYSQL_UNUSED VALUE self) {
  rb_raise(cMysql2Error, "Raw access to the mysql file descriptor isn't supported on Windows");
}

#ssl_cipherObject



388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
# File 'ext/mysql2/client.c', line 388

static VALUE rb_mysql_get_ssl_cipher(VALUE self)
{
  const char *cipher;
  VALUE rb_str;
  GET_CLIENT(self);

  cipher = mysql_get_ssl_cipher(wrapper->client);

  if (cipher == NULL) {
    return Qnil;
  }

  rb_str = rb_str_new2(cipher);
#ifdef HAVE_RUBY_ENCODING_H
  rb_enc_associate(rb_str, rb_utf8_encoding());
#endif

  return rb_str;
}

#store_resultObject

Return the next result object from a query which yielded multiple result sets.



1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
# File 'ext/mysql2/client.c', line 1126

static VALUE rb_mysql_client_store_result(VALUE self)
{
  MYSQL_RES * result;
  VALUE resultObj;
  VALUE current;
  GET_CLIENT(self);

  result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);

  if (result == NULL) {
    if (mysql_errno(wrapper->client) != 0) {
      rb_raise_mysql2_error(wrapper);
    }
    /* no data and no error, so query was not a SELECT */
    return Qnil;
  }

  current = rb_hash_dup(rb_iv_get(self, "@current_query_options"));
  (void)RB_GC_GUARD(current);
  Check_Type(current, T_HASH);
  resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);

  return resultObj;
}

#thread_idObject

Returns the thread ID of the current connection.



1021
1022
1023
1024
1025
1026
1027
1028
# File 'ext/mysql2/client.c', line 1021

static VALUE rb_mysql_client_thread_id(VALUE self) {
  unsigned long retVal;
  GET_CLIENT(self);

  REQUIRE_CONNECTED(wrapper);
  retVal = mysql_thread_id(wrapper->client);
  return ULL2NUM(retVal);
}

#warning_countObject



360
361
362
363
364
365
366
367
# File 'ext/mysql2/client.c', line 360

static VALUE rb_mysql_client_warning_count(VALUE self) {
  unsigned int warning_count;
  GET_CLIENT(self);

  warning_count = mysql_warning_count(wrapper->client);

  return UINT2NUM(warning_count);
}