Class: Mysql2::Client

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

Direct Known Subclasses

EM::Client, Fibered::Client

Constant Summary collapse

CHARSET_MAP =
{
  "armscii8" => nil,
  "ascii"    => Encoding::US_ASCII,
  "big5"     => Encoding::Big5,
  "binary"   => Encoding::ASCII_8BIT,
  "cp1250"   => Encoding::Windows_1250,
  "cp1251"   => Encoding::Windows_1251,
  "cp1256"   => Encoding::Windows_1256,
  "cp1257"   => Encoding::Windows_1257,
  "cp850"    => Encoding::CP850,
  "cp852"    => Encoding::CP852,
  "cp866"    => Encoding::IBM866,
  "cp932"    => Encoding::Windows_31J,
  "dec8"     => nil,
  "eucjpms"  => Encoding::EucJP_ms,
  "euckr"    => Encoding::EUC_KR,
  "gb2312"   => Encoding::EUC_CN,
  "gbk"      => Encoding::GBK,
  "geostd8"  => nil,
  "greek"    => Encoding::ISO_8859_7,
  "hebrew"   => Encoding::ISO_8859_8,
  "hp8"      => nil,
  "keybcs2"  => nil,
  "koi8r"    => Encoding::KOI8_R,
  "koi8u"    => Encoding::KOI8_U,
  "latin1"   => Encoding::ISO_8859_1,
  "latin2"   => Encoding::ISO_8859_2,
  "latin5"   => Encoding::ISO_8859_9,
  "latin7"   => Encoding::ISO_8859_13,
  "macce"    => Encoding::MacCentEuro,
  "macroman" => Encoding::MacRoman,
  "sjis"     => Encoding::SHIFT_JIS,
  "swe7"     => nil,
  "tis620"   => Encoding::TIS_620,
  "ucs2"     => Encoding::UTF_16BE,
  "ujis"     => Encoding::EucJP_ms,
  "utf8"     => Encoding::UTF_8,
}
MYSQL_CHARSET_MAP =
{
  1 => {:name => "big5",      :collation => "big5_chinese_ci"},
  2 => {:name => "latin2",    :collation => "latin2_czech_cs"},
  3 => {:name => "dec8",      :collation => "dec8_swedish_ci"},
  4 => {:name => "cp850",     :collation => "cp850_general_ci"},
  5 => {:name => "latin1",    :collation => "latin1_german1_ci"},
  6 => {:name => "hp8",       :collation => "hp8_english_ci"},
  7 => {:name => "koi8r",     :collation => "koi8r_general_ci"},
  8 => {:name => "latin1",    :collation => "latin1_swedish_ci"},
  9 => {:name => "latin2",    :collation => "latin2_general_ci"},
  10 => {:name => "swe7",     :collation => "swe7_swedish_ci"},
  11 => {:name => "ascii",    :collation => "ascii_general_ci"},
  12 => {:name => "ujis",     :collation => "ujis_japanese_ci"},
  13 => {:name => "sjis",     :collation => "sjis_japanese_ci"},
  14 => {:name => "cp1251",   :collation => "cp1251_bulgarian_ci"},
  15 => {:name => "latin1",   :collation => "latin1_danish_ci"},
  16 => {:name => "hebrew",   :collation => "hebrew_general_ci"},
  17 => {:name => "filename", :collation => "filename"},
  18 => {:name => "tis620",   :collation => "tis620_thai_ci"},
  19 => {:name => "euckr",    :collation => "euckr_korean_ci"},
  20 => {:name => "latin7",   :collation => "latin7_estonian_cs"},
  21 => {:name => "latin2",   :collation => "latin2_hungarian_ci"},
  22 => {:name => "koi8u",    :collation => "koi8u_general_ci"},
  23 => {:name => "cp1251",   :collation => "cp1251_ukrainian_ci"},
  24 => {:name => "gb2312",   :collation => "gb2312_chinese_ci"},
  25 => {:name => "greek",    :collation => "greek_general_ci"},
  26 => {:name => "cp1250",   :collation => "cp1250_general_ci"},
  27 => {:name => "latin2",   :collation => "latin2_croatian_ci"},
  28 => {:name => "gbk",      :collation => "gbk_chinese_ci"},
  29 => {:name => "cp1257",   :collation => "cp1257_lithuanian_ci"},
  30 => {:name => "latin5",   :collation => "latin5_turkish_ci"},
  31 => {:name => "latin1",   :collation => "latin1_german2_ci"},
  32 => {:name => "armscii8", :collation => "armscii8_general_ci"},
  33 => {:name => "utf8",     :collation => "utf8_general_ci"},
  34 => {:name => "cp1250",   :collation => "cp1250_czech_cs"},
  35 => {:name => "ucs2",     :collation => "ucs2_general_ci"},
  36 => {:name => "cp866",    :collation => "cp866_general_ci"},
  37 => {:name => "keybcs2",  :collation => "keybcs2_general_ci"},
  38 => {:name => "macce",    :collation => "macce_general_ci"},
  39 => {:name => "macroman", :collation => "macroman_general_ci"},
  40 => {:name => "cp852",    :collation => "cp852_general_ci"},
  41 => {:name => "latin7",   :collation => "latin7_general_ci"},
  42 => {:name => "latin7",   :collation => "latin7_general_cs"},
  43 => {:name => "macce",    :collation => "macce_bin"},
  44 => {:name => "cp1250",   :collation => "cp1250_croatian_ci"},
  47 => {:name => "latin1",   :collation => "latin1_bin"},
  48 => {:name => "latin1",   :collation => "latin1_general_ci"},
  49 => {:name => "latin1",   :collation => "latin1_general_cs"},
  50 => {:name => "cp1251",   :collation => "cp1251_bin"},
  51 => {:name => "cp1251",   :collation => "cp1251_general_ci"},
  52 => {:name => "cp1251",   :collation => "cp1251_general_cs"},
  53 => {:name => "macroman", :collation => "macroman_bin"},
  57 => {:name => "cp1256",   :collation => "cp1256_general_ci"},
  58 => {:name => "cp1257",   :collation => "cp1257_bin"},
  59 => {:name => "cp1257",   :collation => "cp1257_general_ci"},
  63 => {:name => "binary",   :collation => "binary"},
  64 => {:name => "armscii8", :collation => "armscii8_bin"},
  65 => {:name => "ascii",    :collation => "ascii_bin"},
  66 => {:name => "cp1250",   :collation => "cp1250_bin"},
  67 => {:name => "cp1256",   :collation => "cp1256_bin"},
  68 => {:name => "cp866",    :collation => "cp866_bin"},
  69 => {:name => "dec8",     :collation => "dec8_bin"},
  70 => {:name => "greek",    :collation => "greek_bin"},
  71 => {:name => "hebrew",   :collation => "hebrew_bin"},
  72 => {:name => "hp8",      :collation => "hp8_bin"},
  73 => {:name => "keybcs2",  :collation => "keybcs2_bin"},
  74 => {:name => "koi8r",    :collation => "koi8r_bin"},
  75 => {:name => "koi8u",    :collation => "koi8u_bin"},
  77 => {:name => "latin2",   :collation => "latin2_bin"},
  78 => {:name => "latin5",   :collation => "latin5_bin"},
  79 => {:name => "latin7",   :collation => "latin7_bin"},
  80 => {:name => "cp850",    :collation => "cp850_bin"},
  81 => {:name => "cp852",    :collation => "cp852_bin"},
  82 => {:name => "swe7",     :collation => "swe7_bin"},
  83 => {:name => "utf8",     :collation => "utf8_bin"},
  84 => {:name => "big5",     :collation => "big5_bin"},
  85 => {:name => "euckr",    :collation => "euckr_bin"},
  86 => {:name => "gb2312",   :collation => "gb2312_bin"},
  87 => {:name => "gbk",      :collation => "gbk_bin"},
  88 => {:name => "sjis",     :collation => "sjis_bin"},
  89 => {:name => "tis620",   :collation => "tis620_bin"},
  90 => {:name => "ucs2",     :collation => "ucs2_bin"},
  91 => {:name => "ujis",     :collation => "ujis_bin"},
  92 => {:name => "geostd8",  :collation => "geostd8_general_ci"},
  93 => {:name => "geostd8",  :collation => "geostd8_bin"},
  94 => {:name => "latin1",   :collation => "latin1_spanish_ci"},
  95 => {:name => "cp932",    :collation => "cp932_japanese_ci"},
  96 => {:name => "cp932",    :collation => "cp932_bin"},
  97 => {:name => "eucjpms",  :collation => "eucjpms_japanese_ci"},
  98 => {:name => "eucjpms",  :collation => "eucjpms_bin"},
  99 => {:name => "cp1250",   :collation => "cp1250_polish_ci"},
  128 => {:name => "ucs2",    :collation => "ucs2_unicode_ci"},
  129 => {:name => "ucs2",    :collation => "ucs2_icelandic_ci"},
  130 => {:name => "ucs2",    :collation => "ucs2_latvian_ci"},
  131 => {:name => "ucs2",    :collation => "ucs2_romanian_ci"},
  132 => {:name => "ucs2",    :collation => "ucs2_slovenian_ci"},
  133 => {:name => "ucs2",    :collation => "ucs2_polish_ci"},
  134 => {:name => "ucs2",    :collation => "ucs2_estonian_ci"},
  135 => {:name => "ucs2",    :collation => "ucs2_spanish_ci"},
  136 => {:name => "ucs2",    :collation => "ucs2_swedish_ci"},
  137 => {:name => "ucs2",    :collation => "ucs2_turkish_ci"},
  138 => {:name => "ucs2",    :collation => "ucs2_czech_ci"},
  139 => {:name => "ucs2",    :collation => "ucs2_danish_ci"},
  140 => {:name => "ucs2",    :collation => "ucs2_lithuanian_ci"},
  141 => {:name => "ucs2",    :collation => "ucs2_slovak_ci"},
  142 => {:name => "ucs2",    :collation => "ucs2_spanish2_ci"},
  143 => {:name => "ucs2",    :collation => "ucs2_roman_ci"},
  144 => {:name => "ucs2",    :collation => "ucs2_persian_ci"},
  145 => {:name => "ucs2",    :collation => "ucs2_esperanto_ci"},
  146 => {:name => "ucs2",    :collation => "ucs2_hungarian_ci"},
  192 => {:name => "utf8",    :collation => "utf8_unicode_ci"},
  193 => {:name => "utf8",    :collation => "utf8_icelandic_ci"},
  194 => {:name => "utf8",    :collation => "utf8_latvian_ci"},
  195 => {:name => "utf8",    :collation => "utf8_romanian_ci"},
  196 => {:name => "utf8",    :collation => "utf8_slovenian_ci"},
  197 => {:name => "utf8",    :collation => "utf8_polish_ci"},
  198 => {:name => "utf8",    :collation => "utf8_estonian_ci"},
  199 => {:name => "utf8",    :collation => "utf8_spanish_ci"},
  200 => {:name => "utf8",    :collation => "utf8_swedish_ci"},
  201 => {:name => "utf8",    :collation => "utf8_turkish_ci"},
  202 => {:name => "utf8",    :collation => "utf8_czech_ci"},
  203 => {:name => "utf8",    :collation => "utf8_danish_ci"},
  204 => {:name => "utf8",    :collation => "utf8_lithuanian_ci"},
  205 => {:name => "utf8",    :collation => "utf8_slovak_ci"},
  206 => {:name => "utf8",    :collation => "utf8_spanish2_ci"},
  207 => {:name => "utf8",    :collation => "utf8_roman_ci"},
  208 => {:name => "utf8",    :collation => "utf8_persian_ci"},
  209 => {:name => "utf8",    :collation => "utf8_esperanto_ci"},
  210 => {:name => "utf8",    :collation => "utf8_hungarian_ci"},
  254 => {:name => "utf8",    :collation => "utf8_general_cs"}
}
@@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
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Client

Returns a new instance of Client.



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

def initialize(opts = {})
  @query_options = @@default_query_options.dup

  init_connection

  [:reconnect, :connect_timeout].each do |key|
    next unless opts.key?(key)
    send(:"#{key}=", opts[key])
  end
  # force the encoding to utf8
  self.charset_name = opts[:encoding] || 'utf8'

  @read_timeout = opts[:read_timeout]
  if @read_timeout and @read_timeout < 0
    raise Mysql2::Error, "read_timeout must be a positive integer, you passed #{@read_timeout}"
  end

  ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslciper))

  user     = opts[:username]
  pass     = opts[:password]
  host     = opts[:host] || 'localhost'
  port     = opts[:port] || 3306
  database = opts[:database]
  socket   = opts[:socket]
  flags    = opts[:flags] ? opts[:flags] | @query_options[:connect_flags] : @query_options[:connect_flags]

  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

Class Method Details

.default_query_optionsObject



46
47
48
# File 'lib/mysql2/client.rb', line 46

def self.default_query_options
  @@default_query_options
end

.encoding_from_charset(charset) ⇒ Object



223
224
225
# File 'lib/mysql2/client.rb', line 223

def self.encoding_from_charset(charset)
  CHARSET_MAP[charset.to_s.downcase]
end

.encoding_from_charset_code(code) ⇒ Object



227
228
229
230
231
232
233
# File 'lib/mysql2/client.rb', line 227

def self.encoding_from_charset_code(code)
  if mapping = MYSQL_CHARSET_MAP[code]
    encoding_from_charset(mapping[:name])
  else
    nil
  end
end

.escape(str) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'ext/mysql2/client.c', line 170

static VALUE rb_mysql_client_escape(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

#affected_rowsObject



520
521
522
523
524
525
526
527
528
529
530
# File 'ext/mysql2/client.c', line 520

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

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

#async_resultObject



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'ext/mysql2/client.c', line 266

static VALUE rb_mysql_client_async_result(VALUE self) {
  MYSQL_RES * result;
  VALUE resultObj;
#ifdef HAVE_RUBY_ENCODING_H
  mysql2_result_wrapper * result_wrapper;
#endif
  GET_CLIENT(self);

  REQUIRE_OPEN_DB(wrapper);
  if (rb_thread_blocking_region(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);
  }

  result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, wrapper->client, RUBY_UBF_IO, 0);

  // we have our result, mark this connection inactive
  MARK_CONN_INACTIVE(self);

  if (result == NULL) {
    if (mysql_field_count(wrapper->client) != 0) {
      rb_raise_mysql2_error(wrapper);
    }
    return Qnil;
  }

  resultObj = rb_mysql_result_to_obj(result);
  // pass-through query options for result construction later
  rb_iv_set(resultObj, "@query_options", rb_funcall(rb_iv_get(self, "@query_options"), rb_intern("dup"), 0));

#ifdef HAVE_RUBY_ENCODING_H
  GetMysql2Result(resultObj, result_wrapper);
  result_wrapper->encoding = wrapper->encoding;
#endif
  return resultObj;
}

#closeObject

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.



222
223
224
225
226
227
228
229
230
# File 'ext/mysql2/client.c', line 222

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

  if (!wrapper->closed) {
    rb_thread_blocking_region(nogvl_close, wrapper, RUBY_UBF_IO, 0);
  }

  return Qnil;
}

#encodingObject



558
559
560
561
# File 'ext/mysql2/client.c', line 558

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

#escape(str) ⇒ Object



410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
# File 'ext/mysql2/client.c', line 410

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

#infoObject



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
# File 'ext/mysql2/client.c', line 450

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;
#endif
  GET_CLIENT(self);
  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;
}

#last_idObject



514
515
516
517
518
# File 'ext/mysql2/client.c', line 514

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

#pingObject



547
548
549
550
551
552
553
554
555
# File 'ext/mysql2/client.c', line 547

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

  if (wrapper->closed) {
    return Qfalse;
  } else {
    return rb_thread_blocking_region(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
  }
}

#query(*args) ⇒ Object



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
# File 'ext/mysql2/client.c', line 304

static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
  struct nogvl_send_query_args args;
  fd_set fdset;
  int fd, retval;
  int async = 0;
  VALUE opts, defaults, read_timeout;
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *conn_enc;
#endif
  struct timeval tv;
  struct timeval* tvp;
  long int sec;
  VALUE result;
  GET_CLIENT(self);

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

  // see if this connection is still waiting on a result from a previous query
  if (wrapper->active == 0) {
    // mark this connection active
    wrapper->active = 1;
  } else {
    rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
  }

  defaults = rb_iv_get(self, "@query_options");
  if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
    opts = rb_funcall(defaults, intern_merge, 1, opts);
    rb_iv_set(self, "@query_options", opts);

    if (rb_hash_aref(opts, sym_async) == Qtrue) {
      async = 1;
    }
  } else {
    opts = defaults;
  }

  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

  if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
    // an error occurred, we're not active anymore
    MARK_CONN_INACTIVE(self);
    return rb_raise_mysql2_error(wrapper);
  }

#ifndef _WIN32
  read_timeout = rb_iv_get(self, "@read_timeout");

  tvp = NULL;
  if (!NIL_P(read_timeout)) {
    Check_Type(read_timeout, T_FIXNUM);
    tvp = &tv;
    sec = FIX2INT(read_timeout);
    // TODO: support partial seconds?
    // also, this check is here for sanity, we also check up in Ruby
    if (sec >= 0) {
      tvp->tv_sec = sec;
    } else {
      rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
    }
    tvp->tv_usec = 0;
  }

  if (!async) {
    // the below code is largely from do_mysql
    // http://github.com/datamapper/do
    fd = wrapper->client->net.fd;
    for(;;) {
      int fd_set_fd = fd;

      FD_ZERO(&fdset);
      FD_SET(fd_set_fd, &fdset);

      retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp);

      if (retval == 0) {
        rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
      }

      if (retval < 0) {
        rb_sys_fail(0);
      }

      if (retval > 0) {
        break;
      }
    }

    result = rb_mysql_client_async_result(self);

    return result;
  } else {
    return Qnil;
  }
#else
  // this will just block until the result is ready
  return rb_mysql_client_async_result(self);
#endif
}

#server_infoObject



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
# File 'ext/mysql2/client.c', line 476

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_OPEN_DB(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



503
504
505
506
507
508
509
510
511
512
# File 'ext/mysql2/client.c', line 503

static VALUE rb_mysql_client_socket(VALUE self) {
  GET_CLIENT(self);
#ifndef _WIN32
  REQUIRE_OPEN_DB(wrapper);
  int 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
}

#thread_idObject



532
533
534
535
536
537
538
539
# File 'ext/mysql2/client.c', line 532

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

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