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
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Client

Returns a new instance of Client.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/mysql2/client.rb', line 15

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'

  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



40
41
42
# File 'lib/mysql2/client.rb', line 40

def self.default_query_options
  @@default_query_options
end

.encoding_from_charset(charset) ⇒ Object



217
218
219
# File 'lib/mysql2/client.rb', line 217

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

.encoding_from_charset_code(code) ⇒ Object



221
222
223
224
225
226
227
# File 'lib/mysql2/client.rb', line 221

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

Instance Method Details

#affected_rowsObject



421
422
423
424
425
426
427
428
429
430
431
# File 'ext/mysql2/client.c', line 421

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

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

#async_resultObject



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'ext/mysql2/client.c', line 227

static VALUE rb_mysql_client_async_result(VALUE self) {
  MYSQL_RES * result;
  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->client);
  }

  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->client);
    }
    return Qnil;
  }

  VALUE 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
  mysql2_result_wrapper * result_wrapper;
  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.



183
184
185
186
187
188
189
190
191
# File 'ext/mysql2/client.c', line 183

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

#escape(str) ⇒ Object



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

static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
  VALUE newStr;
  unsigned long newLen, oldLen;
  GET_CLIENT(self);

  REQUIRE_OPEN_DB(wrapper);
  Check_Type(str, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *default_internal_enc = rb_default_internal_encoding();
  rb_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 = rb_str_new(0, oldLen*2+1);

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

#infoObject



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

static VALUE rb_mysql_client_info(VALUE self) {
  VALUE version = rb_hash_new(), client_info;
  GET_CLIENT(self);

#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *default_internal_enc = rb_default_internal_encoding();
  rb_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



415
416
417
418
419
# File 'ext/mysql2/client.c', line 415

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

#query(*args) ⇒ Object



262
263
264
265
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
303
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
# File 'ext/mysql2/client.c', line 262

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

#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *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->client);
  }

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

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

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

      if (retval > 0) {
        break;
      }
    }

    VALUE result = rb_mysql_client_async_result(self);

    return result;
  } else {
    return Qnil;
  }
}

#server_infoObject



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

static VALUE rb_mysql_client_server_info(VALUE self) {
  VALUE version, server_info;
  GET_CLIENT(self);

  REQUIRE_OPEN_DB(wrapper);
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *default_internal_enc = rb_default_internal_encoding();
  rb_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



409
410
411
412
413
# File 'ext/mysql2/client.c', line 409

static VALUE rb_mysql_client_socket(VALUE self) {
  GET_CLIENT(self);
  REQUIRE_OPEN_DB(wrapper);
  return INT2NUM(wrapper->client->net.fd);
}