Class: Mysql2::Client

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

Direct Known Subclasses

EM::Client

Constant Summary

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

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Client) initialize(opts = {})

Returns a new instance of Client



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

def initialize(opts = {})
  opts = Mysql2::Util.key_hash_as_symbols( opts )
  @read_timeout = nil
  @query_options = @@default_query_options.dup
  @query_options.merge! opts

  initialize_ext

  [:reconnect, :connect_timeout, :local_infile, :read_timeout, :write_timeout, :default_file, :default_group, :secure_auth].each do |key|
    next unless opts.key?(key)
    case key
    when :reconnect, :local_infile, :secure_auth
      send(:#{key}=", !!opts[key])
    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?

  if [:user,:pass,:hostname,:dbname,:db,:sock].any?{|k| @query_options.has_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]
  flags    = opts[:flags] ? opts[:flags] | @query_options[:connect_flags] : @query_options[:connect_flags]

  # 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

- (Object) query_options (readonly)

Returns the value of attribute query_options



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

def query_options
  @query_options
end

- (Object) read_timeout (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

+ (Object) default_query_options



70
71
72
# File 'lib/mysql2/client.rb', line 70

def self.default_query_options
  @@default_query_options
end

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

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.



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'ext/mysql2/client.c', line 272

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, StringValuePtr(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;
  }
}

Instance Method Details

- (Object) abandon_results!

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.



580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
# File 'ext/mysql2/client.c', line 580

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

- (Object) affected_rows

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



901
902
903
904
905
906
907
908
909
910
911
# File 'ext/mysql2/client.c', line 901

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

- (Object) async_result

Returns the result for the last async issued query.



439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
# File 'ext/mysql2/client.c', line 439

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"));
  RB_GC_GUARD(current);
  Check_Type(current, T_HASH);
  resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result);

  return resultObj;
}

- (Object) close

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.



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

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

- (Object) encoding

Returns the encoding set on the client.



1054
1055
1056
1057
# File 'ext/mysql2/client.c', line 1054

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

- (Object) escape(string)

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



688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
# File 'ext/mysql2/client.c', line 688

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, StringValuePtr(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_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;
  }
}

- (Object) info

Returns a string that represents the client library version.



806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
# File 'ext/mysql2/client.c', line 806

static VALUE rb_mysql_client_info(VALUE self) {
  VALUE version, client_info;
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *default_internal_enc;
  rb_encoding *conn_enc;
  GET_CLIENT(self);
#endif
  version = rb_hash_new();

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

  rb_hash_aset(version, sym_id, LONG2NUM(mysql_get_client_version()));
  client_info = rb_str_new2(mysql_get_client_info());
#ifdef HAVE_RUBY_ENCODING_H
  rb_enc_associate(client_info, conn_enc);
  if (default_internal_enc) {
    client_info = rb_str_export_to_enc(client_info, default_internal_enc);
  }
#endif
  rb_hash_aset(version, sym_version, client_info);
  return version;
}

- (Object) last_id

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



889
890
891
892
893
# File 'ext/mysql2/client.c', line 889

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

- (Boolean) more_results?

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

Returns:

  • (Boolean)


987
988
989
990
991
992
993
994
# File 'ext/mysql2/client.c', line 987

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

- (Object) next_result

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



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

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

- (Object) ping

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.



972
973
974
975
976
977
978
979
980
# File 'ext/mysql2/client.c', line 972

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

- (Object) query(sql, options = {})

Query the database with sql, with optional options. For the possible options, see @@default_query_options on the Mysql2::Client class.



608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
# File 'ext/mysql2/client.c', line 608

static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
#ifndef _WIN32
  struct async_query_args async_args;
#endif
  struct nogvl_send_query_args args;
  int async = 0;
  VALUE opts, current;
  VALUE thread_current = rb_thread_current();
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *conn_enc;
#endif
  GET_CLIENT(self);

  REQUIRE_CONNECTED(wrapper);
  args.mysql = wrapper->client;

  current = rb_hash_dup(rb_iv_get(self, "@query_options"));
  RB_GC_GUARD(current);
  Check_Type(current, T_HASH);
  rb_iv_set(self, "@current_query_options", current);

  if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
    rb_funcall(current, intern_merge_bang, 1, opts);

    if (rb_hash_aref(current, sym_async) == Qtrue) {
      async = 1;
    }
  }

  Check_Type(args.sql, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
  conn_enc = rb_to_encoding(wrapper->encoding);
  /* ensure the string is in the encoding the connection is expecting */
  args.sql = rb_str_export_to_enc(args.sql, conn_enc);
#endif
  args.sql_ptr = StringValuePtr(args.sql);
  args.sql_len = RSTRING_LEN(args.sql);

  /* see if this connection is still waiting on a result from a previous query */
  if (NIL_P(wrapper->active_thread)) {
    /* mark this connection active */
    wrapper->active_thread = thread_current;
  } else if (wrapper->active_thread == thread_current) {
    rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
  } else {
    VALUE inspect = rb_inspect(wrapper->active_thread);
    const char *thr = StringValueCStr(inspect);

    rb_raise(cMysql2Error, "This connection is in use by: %s", thr);
    RB_GC_GUARD(inspect);
  }

  args.wrapper = wrapper;

#ifndef _WIN32
  rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);

  if (!async) {
    async_args.fd = wrapper->client->net.fd;
    async_args.self = self;

    rb_rescue2(do_query, (VALUE)&async_args, disconnect_and_raise, self, rb_eException, (VALUE)0);

    return rb_mysql_client_async_result(self);
  } else {
    return Qnil;
  }
#else
  do_send_query(&args);

  /* this will just block until the result is ready */
  return rb_ensure(rb_mysql_client_async_result, self, finish_and_mark_inactive, self);
#endif
}

- (Object) query_info



74
75
76
77
78
79
80
# File 'lib/mysql2/client.rb', line 74

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

- (Object) query_info_string



306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'ext/mysql2/client.c', line 306

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

- (Object) reconnect=(true)

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



1067
1068
1069
# File 'ext/mysql2/client.c', line 1067

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

- (Object) select_db(name)

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



942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
# File 'ext/mysql2/client.c', line 942

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 = StringValuePtr(db);

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

  return db;
}

- (Object) server_info

Returns a string that represents the server version number



837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
# File 'ext/mysql2/client.c', line 837

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

- (Object) socket

Return the file descriptor number for this client.



869
870
871
872
873
874
875
876
877
878
879
880
881
# File 'ext/mysql2/client.c', line 869

static VALUE rb_mysql_client_socket(VALUE self) {
  GET_CLIENT(self);
#ifndef _WIN32
  {
    int fd_set_fd;
    REQUIRE_CONNECTED(wrapper);
    fd_set_fd = wrapper->client->net.fd;
    return INT2NUM(fd_set_fd);
  }
#else
  rb_raise(cMysql2Error, "Raw access to the mysql file descriptor isn't supported on Windows");
#endif
}

- (Object) store_result

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



1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
# File 'ext/mysql2/client.c', line 1023

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"));
  RB_GC_GUARD(current);
  Check_Type(current, T_HASH);
  resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result);

  return resultObj;
}

- (Object) thread_id

Returns the thread ID of the current connection.



918
919
920
921
922
923
924
925
# File 'ext/mysql2/client.c', line 918

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

- (Object) warning_count



297
298
299
300
301
302
303
304
# File 'ext/mysql2/client.c', line 297

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