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



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
# File 'lib/mysql2/client.rb', line 21

def initialize(opts = {})
  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].each do |key|
    next unless opts.key?(key)
    case key
    when :reconnect, :local_infile, :secure_auth
      send(:#{key}=", !!opts[key]) # rubocop:disable Style/DoubleNegation
    when :connect_timeout, :read_timeout, :write_timeout
      send(:#{key}=", opts[key].to_i)
    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?

  # SSL verify is a connection flag rather than a mysql_ssl_set option
  flags = 0
  flags |= @query_options[:connect_flags]
  flags |= opts[:flags] if opts[:flags]
  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 it's 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.



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'ext/mysql2/client.c', line 281

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.



843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
# File 'ext/mysql2/client.c', line 843

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.



628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
# File 'ext/mysql2/client.c', line 628

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.



929
930
931
932
933
934
935
936
937
938
939
# File 'ext/mysql2/client.c', line 929

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.



471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
# File 'ext/mysql2/client.c', line 471

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 */
    MARK_CONN_INACTIVE(self);
    return 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) {
      MARK_CONN_INACTIVE(self);
      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;
}

#closevoid

This method returns an undefined value.

Terminate the connection; call this when the connection is no longer needed. The garbage collector can close the connection, but doing so emits an “Aborted connection” error on the server and increments the Aborted_clients status variable.



392
393
394
395
396
397
398
399
400
# File 'ext/mysql2/client.c', line 392

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.



1082
1083
1084
1085
# File 'ext/mysql2/client.c', line 1082

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.



709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
# File 'ext/mysql2/client.c', line 709

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



102
103
104
# File 'lib/mysql2/client.rb', line 102

def info
  self.class.info
end

#last_idObject

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



917
918
919
920
921
# File 'ext/mysql2/client.c', line 917

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.



1015
1016
1017
1018
1019
1020
1021
1022
# File 'ext/mysql2/client.c', line 1015

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.



1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
# File 'ext/mysql2/client.c', line 1030

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;
    }
}

#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.



1000
1001
1002
1003
1004
1005
1006
1007
1008
# File 'ext/mysql2/client.c', line 1000

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);
  }
}

#prepareObject

Create a new prepared statement.



1213
1214
1215
1216
1217
1218
# File 'ext/mysql2/client.c', line 1213

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



83
84
85
86
87
# File 'lib/mysql2/client.rb', line 83

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

#query_infoObject



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

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



315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'ext/mysql2/client.c', line 315

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.



1095
1096
1097
# File 'ext/mysql2/client.c', line 1095

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.



970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
# File 'ext/mysql2/client.c', line 970

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



867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
# File 'ext/mysql2/client.c', line 867

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



906
907
908
# File 'ext/mysql2/client.c', line 906

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");
}

#store_resultObject

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



1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
# File 'ext/mysql2/client.c', line 1051

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.



946
947
948
949
950
951
952
953
# File 'ext/mysql2/client.c', line 946

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



306
307
308
309
310
311
312
313
# File 'ext/mysql2/client.c', line 306

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);
}