mysql2 0.3.12b4 → 0.3.12b5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,37 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.12 (not yet released)
4
+ ## 0.3.12b5 (not yet released)
5
+ * builds on Ruby 2.0-head and Rubinius 2.0-dev
6
+ * encoding names now stored in a Gperf lookup rather than an array
7
+ * long-standing bug fix: options set on a single query must not be applied to subsequent queries
8
+ * add method warning_count
9
+ * add method abandon_results!
10
+ * add setter for reconnect option
11
+ * remove options method (added in 0.3.12b1)
12
+ * support microsecond Time resolution
13
+ * several INT / UINT fixes
14
+
15
+ ## 0.3.12b4 (August 22, 2012)
16
+ * add write_timeout as well
17
+
18
+ ## 0.3.12b3 (August 22, 2012)
19
+ * several INT / LONG fixes
20
+ * fix linking to MySQL 5.5
21
+
22
+ ## 0.3.12b2 (August 10, 2012)
23
+ * more_results is now more_results?
24
+
25
+ ## 0.3.12b1 (August 8, 2012)
26
+ * several threading and async bug fixes
27
+ * better handling of read and write timeouts
28
+ * add :local_infile connection option
29
+ * add MULTI_STATEMENTS connection flag and methods store_result, next_result, more_results
30
+ * add select_db and options methods
31
+ * add :stream query option
32
+ * add support for utf8mb4 encoding
33
+ * deprecation warnings for the :user, :pass, :hostname, :dbname, :db, :sock connection options
34
+
3
35
  ## 0.3.11 (December 6th, 2011)
4
36
  * change mysql error detection strategy from using mysql_field_count to the more explicit mysql_errno
5
37
  * bugfix to avoid race condition with active connections that error out
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Mysql2 - A modern, simple and very fast Mysql library for Ruby - binding to libmysql
2
2
 
3
+ [![Build Status](https://travis-ci.org/brianmario/mysql2.png)](https://travis-ci.org/brianmario/mysql2)
4
+
3
5
  The Mysql2 gem is meant to serve the extremely common use-case of connecting, querying and iterating on results.
4
6
  Some database libraries out there serve as direct 1:1 mappings of the already complex C API's available.
5
7
  This one is not.
@@ -18,7 +20,9 @@ Mysql2::Result - returned from issuing a #query on the connection. It includes E
18
20
  gem install mysql2
19
21
  ```
20
22
 
21
- You may have to specify --with-mysql-config=/some/random/path/bin/mysql_config
23
+ This gem links against MySQL's `libmysqlclient` C shared library. You may need to install a package such as `libmysqlclient-dev`, `mysql-devel`, or other appropriate package for your system.
24
+
25
+ If you have installed MySQL to a non-standard location, add `gem install mysql2 --with-mysql-config=/some/random/path/bin/mysql_config`
22
26
 
23
27
  ## Usage
24
28
 
@@ -100,6 +104,7 @@ Mysql2::Client.new(
100
104
  :flags = REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION | MULTI_STATEMENTS,
101
105
  :encoding = 'utf8',
102
106
  :read_timeout = seconds,
107
+ :write_timeout = seconds,
103
108
  :connect_timeout = seconds,
104
109
  :reconnect = true/false,
105
110
  :local_infile = true/false,
@@ -120,7 +125,7 @@ while ( client.next_result)
120
125
  end
121
126
  ```
122
127
 
123
- See https://gist.github.com/1367987 for using MULTI_STATEMENTS with ActiveRecord.
128
+ See https://gist.github.com/1367987 for using MULTI_STATEMENTS with Active Record.
124
129
 
125
130
  ## Cascading config
126
131
 
@@ -264,15 +269,15 @@ There are a few things that need to be kept in mind while using streaming:
264
269
 
265
270
  Read more about the consequences of using `mysql_use_result` (what streaming is implemented with) here: http://dev.mysql.com/doc/refman/5.0/en/mysql-use-result.html.
266
271
 
267
- ## ActiveRecord
272
+ ## Active Record
268
273
 
269
- To use the ActiveRecord driver (with or without rails), all you should need to do is have this gem installed and set the adapter in your database.yml to "mysql2".
274
+ To use the Active Record driver (with or without rails), all you should need to do is have this gem installed and set the adapter in your database.yml to "mysql2".
270
275
  That was easy right? :)
271
276
 
272
- NOTE: as of 0.3.0, and ActiveRecord 3.1 - the ActiveRecord adapter has been pulled out of this gem and into ActiveRecord itself. If you need to use mysql2 with
277
+ NOTE: as of 0.3.0, and Active Record 3.1 - the Active Record adapter has been pulled out of this gem and into Active Record itself. If you need to use mysql2 with
273
278
  Rails versions < 3.1 make sure and specify `gem "mysql2", "~> 0.2.7"` in your Gemfile
274
279
 
275
- ## Asynchronous ActiveRecord
280
+ ## Asynchronous Active Record
276
281
 
277
282
  Please see the [em-synchrony](https://github.com/igrigorik/em-synchrony) project for details about using EventMachine with mysql2 and Rails.
278
283
 
@@ -328,7 +333,7 @@ The specs pass on my system (SL 10.6.3, x86_64) in these rubies:
328
333
  * ruby-trunk
329
334
  * rbx-head - broken at the moment, working with the rbx team for a solution
330
335
 
331
- The ActiveRecord driver should work on 2.3.5 and 3.0
336
+ The Active Record driver should work on 2.3.5 and 3.0
332
337
 
333
338
  ## Yeah... but why?
334
339
 
@@ -387,6 +392,7 @@ though.
387
392
  ## Special Thanks
388
393
 
389
394
  * Eric Wong - for the contribution (and the informative explanations) of some thread-safety, non-blocking I/O and cleanup patches. You rock dude
390
- * Yury Korolev (http://github.com/yury) - for TONS of help testing the ActiveRecord adapter
395
+ * Yury Korolev (http://github.com/yury) - for TONS of help testing the Active Record adapter
391
396
  * Aaron Patterson (http://github.com/tenderlove) - tons of contributions, suggestions and general badassness
392
- * Mike Perham (http://github.com/mperham) - Async ActiveRecord adapter (uses Fibers and EventMachine)
397
+ * Mike Perham (http://github.com/mperham) - Async Active Record adapter (uses Fibers and EventMachine)
398
+ * Aaron Stone (http://github.com/sodabrew) - additional client settings, local files, microsecond time, maintenance support.
@@ -4,13 +4,21 @@
4
4
  #ifndef _WIN32
5
5
  #include <sys/socket.h>
6
6
  #endif
7
+ #include <unistd.h>
7
8
  #include "wait_for_single_fd.h"
8
9
 
10
+ #include "mysql_enc_name_to_ruby.h"
11
+
9
12
  VALUE cMysql2Client;
10
13
  extern VALUE mMysql2, cMysql2Error;
11
- static VALUE intern_encoding_from_charset;
12
14
  static VALUE sym_id, sym_version, sym_async, sym_symbolize_keys, sym_as, sym_array, sym_stream;
13
- static ID intern_merge, intern_error_number_eql, intern_sql_state_eql;
15
+ static ID intern_merge, intern_merge_bang, intern_error_number_eql, intern_sql_state_eql;
16
+
17
+ #ifndef HAVE_RB_HASH_DUP
18
+ static VALUE rb_hash_dup(VALUE other) {
19
+ return rb_funcall(rb_cHash, rb_intern("[]"), 1, other);
20
+ }
21
+ #endif
14
22
 
15
23
  #define REQUIRE_INITIALIZED(wrapper) \
16
24
  if (!wrapper->initialized) { \
@@ -190,12 +198,19 @@ static VALUE allocate(VALUE klass) {
190
198
  wrapper->encoding = Qnil;
191
199
  wrapper->active_thread = Qnil;
192
200
  wrapper->reconnect_enabled = 0;
193
- wrapper->connected = 0; // means that a database connection is open
194
- wrapper->initialized = 0; // means that that the wrapper is initialized
201
+ wrapper->connected = 0; /* means that a database connection is open */
202
+ wrapper->initialized = 0; /* means that that the wrapper is initialized */
195
203
  wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
196
204
  return obj;
197
205
  }
198
206
 
207
+ /* call-seq:
208
+ * Mysql2::Client.escape(string)
209
+ *
210
+ * Escape +string+ so that it may be used in a SQL statement.
211
+ * Note that this escape method is not connection encoding aware.
212
+ * If you need encoding support use Mysql2::Client#escape instead.
213
+ */
199
214
  static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
200
215
  unsigned char *newStr;
201
216
  VALUE rb_str;
@@ -208,7 +223,7 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
208
223
 
209
224
  newLen = mysql_escape_string((char *)newStr, StringValuePtr(str), oldLen);
210
225
  if (newLen == oldLen) {
211
- // no need to return a new ruby string if nothing changed
226
+ /* no need to return a new ruby string if nothing changed */
212
227
  xfree(newStr);
213
228
  return str;
214
229
  } else {
@@ -221,6 +236,15 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
221
236
  }
222
237
  }
223
238
 
239
+ static VALUE rb_mysql_client_warning_count(VALUE self) {
240
+ unsigned int warning_count;
241
+ GET_CLIENT(self);
242
+
243
+ warning_count = mysql_warning_count(wrapper->client);
244
+
245
+ return UINT2NUM(warning_count);
246
+ }
247
+
224
248
  static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags) {
225
249
  struct nogvl_connect_args args;
226
250
  VALUE rv;
@@ -283,7 +307,7 @@ static VALUE do_send_query(void *args) {
283
307
  struct nogvl_send_query_args *query_args = args;
284
308
  mysql_client_wrapper *wrapper = query_args->wrapper;
285
309
  if (rb_thread_blocking_region(nogvl_send_query, args, RUBY_UBF_IO, 0) == Qfalse) {
286
- // an error occurred, we're not active anymore
310
+ /* an error occurred, we're not active anymore */
287
311
  MARK_CONN_INACTIVE(self);
288
312
  return rb_raise_mysql2_error(wrapper);
289
313
  }
@@ -313,8 +337,8 @@ static VALUE nogvl_do_result(void *ptr, char use_result) {
313
337
  result = mysql_store_result(wrapper->client);
314
338
  }
315
339
 
316
- // once our result is stored off, this connection is
317
- // ready for another command to be issued
340
+ /* once our result is stored off, this connection is
341
+ ready for another command to be issued */
318
342
  wrapper->active_thread = Qnil;
319
343
 
320
344
  return (VALUE)result;
@@ -342,18 +366,18 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
342
366
  #endif
343
367
  GET_CLIENT(self);
344
368
 
345
- // if we're not waiting on a result, do nothing
369
+ /* if we're not waiting on a result, do nothing */
346
370
  if (NIL_P(wrapper->active_thread))
347
371
  return Qnil;
348
372
 
349
373
  REQUIRE_CONNECTED(wrapper);
350
374
  if (rb_thread_blocking_region(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
351
- // an error occurred, mark this connection inactive
375
+ /* an error occurred, mark this connection inactive */
352
376
  MARK_CONN_INACTIVE(self);
353
377
  return rb_raise_mysql2_error(wrapper);
354
378
  }
355
379
 
356
- VALUE is_streaming = rb_hash_aref(rb_iv_get(self, "@query_options"), sym_stream);
380
+ VALUE is_streaming = rb_hash_aref(rb_iv_get(self, "@current_query_options"), sym_stream);
357
381
  if(is_streaming == Qtrue) {
358
382
  result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_use_result, wrapper, RUBY_UBF_IO, 0);
359
383
  } else {
@@ -365,13 +389,13 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
365
389
  MARK_CONN_INACTIVE(self);
366
390
  rb_raise_mysql2_error(wrapper);
367
391
  }
368
- // no data and no error, so query was not a SELECT
392
+ /* no data and no error, so query was not a SELECT */
369
393
  return Qnil;
370
394
  }
371
395
 
372
396
  resultObj = rb_mysql_result_to_obj(result);
373
- // pass-through query options for result construction later
374
- rb_iv_set(resultObj, "@query_options", rb_funcall(rb_iv_get(self, "@query_options"), rb_intern("dup"), 0));
397
+ /* pass-through query options for result construction later */
398
+ rb_iv_set(resultObj, "@query_options", rb_hash_dup(rb_iv_get(self, "@current_query_options")));
375
399
 
376
400
  #ifdef HAVE_RUBY_ENCODING_H
377
401
  GetMysql2Result(resultObj, result_wrapper);
@@ -392,9 +416,10 @@ static VALUE disconnect_and_raise(VALUE self, VALUE error) {
392
416
  wrapper->active_thread = Qnil;
393
417
  wrapper->connected = 0;
394
418
 
395
- // manually close the socket for read/write
396
- // this feels dirty, but is there another way?
397
- shutdown(wrapper->client->net.fd, 2);
419
+ /* manually close the socket for read/write
420
+ this feels dirty, but is there another way? */
421
+ close(wrapper->client->net.fd);
422
+ wrapper->client->net.fd = -1;
398
423
 
399
424
  rb_exc_raise(error);
400
425
 
@@ -417,8 +442,8 @@ static VALUE do_query(void *args) {
417
442
  Check_Type(read_timeout, T_FIXNUM);
418
443
  tvp = &tv;
419
444
  sec = FIX2INT(read_timeout);
420
- // TODO: support partial seconds?
421
- // also, this check is here for sanity, we also check up in Ruby
445
+ /* TODO: support partial seconds?
446
+ also, this check is here for sanity, we also check up in Ruby */
422
447
  if (sec >= 0) {
423
448
  tvp->tv_sec = sec;
424
449
  } else {
@@ -455,9 +480,9 @@ static VALUE finish_and_mark_inactive(void *args) {
455
480
  GET_CLIENT(self);
456
481
 
457
482
  if (!NIL_P(wrapper->active_thread)) {
458
- // if we got here, the result hasn't been read off the wire yet
459
- // so lets do that and then throw it away because we have no way
460
- // of getting it back up to the caller from here
483
+ /* if we got here, the result hasn't been read off the wire yet
484
+ so lets do that and then throw it away because we have no way
485
+ of getting it back up to the caller from here */
461
486
  result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
462
487
  mysql_free_result(result);
463
488
 
@@ -468,6 +493,36 @@ static VALUE finish_and_mark_inactive(void *args) {
468
493
  }
469
494
  #endif
470
495
 
496
+ /* call-seq:
497
+ * client.abandon_results!
498
+ *
499
+ * When using MULTI_STATEMENTS support, calling this will throw
500
+ * away any unprocessed results as fast as it can in order to
501
+ * put the connection back into a state where queries can be issued
502
+ * again.
503
+ */
504
+ static VALUE rb_mysql_client_abandon_results(VALUE self) {
505
+ GET_CLIENT(self);
506
+
507
+ MYSQL_RES *result;
508
+ int ret;
509
+
510
+ while (mysql_more_results(wrapper->client) == 1) {
511
+ ret = mysql_next_result(wrapper->client);
512
+ if (ret > 0) {
513
+ rb_raise_mysql2_error(wrapper);
514
+ }
515
+
516
+ result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
517
+
518
+ if (result != NULL) {
519
+ mysql_free_result(result);
520
+ }
521
+ }
522
+
523
+ return Qnil;
524
+ }
525
+
471
526
  /* call-seq:
472
527
  * client.query(sql, options = {})
473
528
  *
@@ -480,7 +535,7 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
480
535
  #endif
481
536
  struct nogvl_send_query_args args;
482
537
  int async = 0;
483
- VALUE opts, defaults;
538
+ VALUE opts, current;
484
539
  VALUE thread_current = rb_thread_current();
485
540
  #ifdef HAVE_RUBY_ENCODING_H
486
541
  rb_encoding *conn_enc;
@@ -490,31 +545,28 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
490
545
  REQUIRE_CONNECTED(wrapper);
491
546
  args.mysql = wrapper->client;
492
547
 
493
-
494
- defaults = rb_iv_get(self, "@query_options");
548
+ rb_iv_set(self, "@current_query_options", rb_hash_dup(rb_iv_get(self, "@query_options")));
549
+ current = rb_iv_get(self, "@current_query_options");
495
550
  if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
496
- opts = rb_funcall(defaults, intern_merge, 1, opts);
497
- rb_iv_set(self, "@query_options", opts);
551
+ opts = rb_funcall(current, intern_merge_bang, 1, opts);
498
552
 
499
- if (rb_hash_aref(opts, sym_async) == Qtrue) {
553
+ if (rb_hash_aref(current, sym_async) == Qtrue) {
500
554
  async = 1;
501
555
  }
502
- } else {
503
- opts = defaults;
504
556
  }
505
557
 
506
558
  Check_Type(args.sql, T_STRING);
507
559
  #ifdef HAVE_RUBY_ENCODING_H
508
560
  conn_enc = rb_to_encoding(wrapper->encoding);
509
- // ensure the string is in the encoding the connection is expecting
561
+ /* ensure the string is in the encoding the connection is expecting */
510
562
  args.sql = rb_str_export_to_enc(args.sql, conn_enc);
511
563
  #endif
512
564
  args.sql_ptr = StringValuePtr(args.sql);
513
565
  args.sql_len = RSTRING_LEN(args.sql);
514
566
 
515
- // see if this connection is still waiting on a result from a previous query
567
+ /* see if this connection is still waiting on a result from a previous query */
516
568
  if (NIL_P(wrapper->active_thread)) {
517
- // mark this connection active
569
+ /* mark this connection active */
518
570
  wrapper->active_thread = thread_current;
519
571
  } else if (wrapper->active_thread == thread_current) {
520
572
  rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
@@ -544,7 +596,7 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
544
596
  #else
545
597
  do_send_query(&args);
546
598
 
547
- // this will just block until the result is ready
599
+ /* this will just block until the result is ready */
548
600
  return rb_ensure(rb_mysql_client_async_result, self, finish_and_mark_inactive, self);
549
601
  #endif
550
602
  }
@@ -569,7 +621,7 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
569
621
  #ifdef HAVE_RUBY_ENCODING_H
570
622
  default_internal_enc = rb_default_internal_encoding();
571
623
  conn_enc = rb_to_encoding(wrapper->encoding);
572
- // ensure the string is in the encoding the connection is expecting
624
+ /* ensure the string is in the encoding the connection is expecting */
573
625
  str = rb_str_export_to_enc(str, conn_enc);
574
626
  #endif
575
627
 
@@ -578,7 +630,7 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
578
630
 
579
631
  newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, StringValuePtr(str), oldLen);
580
632
  if (newLen == oldLen) {
581
- // no need to return a new ruby string if nothing changed
633
+ /* no need to return a new ruby string if nothing changed */
582
634
  xfree(newStr);
583
635
  return str;
584
636
  } else {
@@ -639,11 +691,11 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
639
691
 
640
692
  result = mysql_options(wrapper->client, opt, retval);
641
693
 
642
- // Zero means success
694
+ /* Zero means success */
643
695
  if (result != 0) {
644
696
  rb_warn("%s\n", mysql_error(wrapper->client));
645
697
  } else {
646
- // Special case for reconnect, this option is also stored in the wrapper struct
698
+ /* Special case for reconnect, this option is also stored in the wrapper struct */
647
699
  if (opt == MYSQL_OPT_RECONNECT)
648
700
  wrapper->reconnect_enabled = boolval;
649
701
  }
@@ -651,12 +703,6 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
651
703
  return (result == 0) ? Qtrue : Qfalse;
652
704
  }
653
705
 
654
- static VALUE rb_mysql_client_options(VALUE self, VALUE option, VALUE value) {
655
- Check_Type(option, T_FIXNUM);
656
- int opt = NUM2INT(option);
657
- return _mysql_client_options(self, opt, value);
658
- }
659
-
660
706
  /* call-seq:
661
707
  * client.info
662
708
  *
@@ -835,6 +881,11 @@ static VALUE rb_mysql_client_ping(VALUE self) {
835
881
  }
836
882
  }
837
883
 
884
+ /* call-seq:
885
+ * client.more_results?
886
+ *
887
+ * Returns true or false if there are more results to process.
888
+ */
838
889
  static VALUE rb_mysql_client_more_results(VALUE self)
839
890
  {
840
891
  GET_CLIENT(self);
@@ -844,18 +895,33 @@ static VALUE rb_mysql_client_more_results(VALUE self)
844
895
  return Qtrue;
845
896
  }
846
897
 
898
+ /* call-seq:
899
+ * client.next_result
900
+ *
901
+ * Fetch the next result set from the server.
902
+ * Returns nothing.
903
+ */
847
904
  static VALUE rb_mysql_client_next_result(VALUE self)
848
905
  {
849
906
  GET_CLIENT(self);
850
907
  int ret;
851
908
  ret = mysql_next_result(wrapper->client);
852
- if (ret == 0)
909
+ if (ret > 0) {
910
+ rb_raise_mysql2_error(wrapper);
911
+ return Qfalse;
912
+ } else if (ret == 0) {
853
913
  return Qtrue;
854
- else
914
+ } else {
855
915
  return Qfalse;
916
+ }
856
917
  }
857
918
 
858
-
919
+ /* call-seq:
920
+ * client.store_result
921
+ *
922
+ * Return the next result object from a query which
923
+ * yielded multiple result sets.
924
+ */
859
925
  static VALUE rb_mysql_client_store_result(VALUE self)
860
926
  {
861
927
  MYSQL_RES * result;
@@ -864,12 +930,7 @@ static VALUE rb_mysql_client_store_result(VALUE self)
864
930
  mysql2_result_wrapper * result_wrapper;
865
931
  #endif
866
932
 
867
-
868
933
  GET_CLIENT(self);
869
- // MYSQL_RES* res = mysql_store_result(wrapper->client);
870
- // if (res == NULL)
871
- // mysql_raise(wrapper->client);
872
- // return mysqlres2obj(res);
873
934
 
874
935
  result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
875
936
 
@@ -877,13 +938,13 @@ static VALUE rb_mysql_client_store_result(VALUE self)
877
938
  if (mysql_errno(wrapper->client) != 0) {
878
939
  rb_raise_mysql2_error(wrapper);
879
940
  }
880
- // no data and no error, so query was not a SELECT
941
+ /* no data and no error, so query was not a SELECT */
881
942
  return Qnil;
882
943
  }
883
944
 
884
945
  resultObj = rb_mysql_result_to_obj(result);
885
- // pass-through query options for result construction later
886
- rb_iv_set(resultObj, "@query_options", rb_funcall(rb_iv_get(self, "@query_options"), rb_intern("dup"), 0));
946
+ /* pass-through query options for result construction later */
947
+ rb_iv_set(resultObj, "@query_options", rb_hash_dup(rb_iv_get(self, "@current_query_options")));
887
948
 
888
949
  #ifdef HAVE_RUBY_ENCODING_H
889
950
  GetMysql2Result(resultObj, result_wrapper);
@@ -905,6 +966,13 @@ static VALUE rb_mysql_client_encoding(VALUE self) {
905
966
  }
906
967
  #endif
907
968
 
969
+ /* call-seq:
970
+ * client.reconnect = true
971
+ *
972
+ * Enable or disable the automatic reconnect behavior of libmysql.
973
+ * Read http://dev.mysql.com/doc/refman/5.5/en/auto-reconnect.html
974
+ * for more information.
975
+ */
908
976
  static VALUE set_reconnect(VALUE self, VALUE value) {
909
977
  return _mysql_client_options(self, MYSQL_OPT_RECONNECT, value);
910
978
  }
@@ -930,9 +998,9 @@ static VALUE set_read_timeout(VALUE self, VALUE value) {
930
998
  if (sec < 0) {
931
999
  rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
932
1000
  }
933
- // Set the instance variable here even though _mysql_client_options
934
- // might not succeed, because the timeout is used in other ways
935
- // elsewhere
1001
+ /* Set the instance variable here even though _mysql_client_options
1002
+ might not succeed, because the timeout is used in other ways
1003
+ elsewhere */
936
1004
  rb_iv_set(self, "@read_timeout", value);
937
1005
  return _mysql_client_options(self, MYSQL_OPT_READ_TIMEOUT, value);
938
1006
  }
@@ -948,26 +1016,30 @@ static VALUE set_write_timeout(VALUE self, VALUE value) {
948
1016
  }
949
1017
 
950
1018
  static VALUE set_charset_name(VALUE self, VALUE value) {
951
- char * charset_name;
1019
+ char *charset_name;
1020
+ size_t charset_name_len;
1021
+ const struct mysql2_mysql_enc_name_to_rb_map *mysql2rb;
952
1022
  #ifdef HAVE_RUBY_ENCODING_H
953
- VALUE new_encoding;
1023
+ rb_encoding *enc;
1024
+ VALUE rb_enc;
954
1025
  #endif
955
1026
  GET_CLIENT(self);
956
1027
 
1028
+ charset_name = RSTRING_PTR(value);
1029
+ charset_name_len = RSTRING_LEN(value);
1030
+
957
1031
  #ifdef HAVE_RUBY_ENCODING_H
958
- new_encoding = rb_funcall(cMysql2Client, intern_encoding_from_charset, 1, value);
959
- if (new_encoding == Qnil) {
1032
+ mysql2rb = mysql2_mysql_enc_name_to_rb(charset_name, charset_name_len);
1033
+ if (mysql2rb == NULL || mysql2rb->rb_name == NULL) {
960
1034
  VALUE inspect = rb_inspect(value);
961
1035
  rb_raise(cMysql2Error, "Unsupported charset: '%s'", RSTRING_PTR(inspect));
962
1036
  } else {
963
- if (wrapper->encoding == Qnil) {
964
- wrapper->encoding = new_encoding;
965
- }
1037
+ enc = rb_enc_find(mysql2rb->rb_name);
1038
+ rb_enc = rb_enc_from_encoding(enc);
1039
+ wrapper->encoding = rb_enc;
966
1040
  }
967
1041
  #endif
968
1042
 
969
- charset_name = StringValuePtr(value);
970
-
971
1043
  if (mysql_options(wrapper->client, MYSQL_SET_CHARSET_NAME, charset_name)) {
972
1044
  /* TODO: warning - unable to set charset */
973
1045
  rb_warn("%s\n", mysql_error(wrapper->client));
@@ -1004,15 +1076,15 @@ static VALUE initialize_ext(VALUE self) {
1004
1076
  }
1005
1077
 
1006
1078
  void init_mysql2_client() {
1007
- // verify the libmysql we're about to use was the version we were built against
1008
- // https://github.com/luislavena/mysql-gem/commit/a600a9c459597da0712f70f43736e24b484f8a99
1079
+ /* verify the libmysql we're about to use was the version we were built against
1080
+ https://github.com/luislavena/mysql-gem/commit/a600a9c459597da0712f70f43736e24b484f8a99 */
1009
1081
  int i;
1010
1082
  int dots = 0;
1011
1083
  const char *lib = mysql_get_client_info();
1012
1084
  for (i = 0; lib[i] != 0 && MYSQL_SERVER_VERSION[i] != 0; i++) {
1013
1085
  if (lib[i] == '.') {
1014
1086
  dots++;
1015
- // we only compare MAJOR and MINOR
1087
+ /* we only compare MAJOR and MINOR */
1016
1088
  if (dots == 2) break;
1017
1089
  }
1018
1090
  if (lib[i] != MYSQL_SERVER_VERSION[i]) {
@@ -1032,6 +1104,7 @@ void init_mysql2_client() {
1032
1104
 
1033
1105
  rb_define_method(cMysql2Client, "close", rb_mysql_client_close, 0);
1034
1106
  rb_define_method(cMysql2Client, "query", rb_mysql_client_query, -1);
1107
+ rb_define_method(cMysql2Client, "abandon_results!", rb_mysql_client_abandon_results, 0);
1035
1108
  rb_define_method(cMysql2Client, "escape", rb_mysql_client_real_escape, 1);
1036
1109
  rb_define_method(cMysql2Client, "info", rb_mysql_client_info, 0);
1037
1110
  rb_define_method(cMysql2Client, "server_info", rb_mysql_client_server_info, 0);
@@ -1045,12 +1118,12 @@ void init_mysql2_client() {
1045
1118
  rb_define_method(cMysql2Client, "more_results?", rb_mysql_client_more_results, 0);
1046
1119
  rb_define_method(cMysql2Client, "next_result", rb_mysql_client_next_result, 0);
1047
1120
  rb_define_method(cMysql2Client, "store_result", rb_mysql_client_store_result, 0);
1048
- rb_define_method(cMysql2Client, "options", rb_mysql_client_options, 2);
1121
+ rb_define_method(cMysql2Client, "reconnect=", set_reconnect, 1);
1122
+ rb_define_method(cMysql2Client, "warning_count", rb_mysql_client_warning_count, 0);
1049
1123
  #ifdef HAVE_RUBY_ENCODING_H
1050
1124
  rb_define_method(cMysql2Client, "encoding", rb_mysql_client_encoding, 0);
1051
1125
  #endif
1052
1126
 
1053
- rb_define_private_method(cMysql2Client, "reconnect=", set_reconnect, 1);
1054
1127
  rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
1055
1128
  rb_define_private_method(cMysql2Client, "read_timeout=", set_read_timeout, 1);
1056
1129
  rb_define_private_method(cMysql2Client, "write_timeout=", set_write_timeout, 1);
@@ -1060,8 +1133,6 @@ void init_mysql2_client() {
1060
1133
  rb_define_private_method(cMysql2Client, "initialize_ext", initialize_ext, 0);
1061
1134
  rb_define_private_method(cMysql2Client, "connect", rb_connect, 7);
1062
1135
 
1063
- intern_encoding_from_charset = rb_intern("encoding_from_charset");
1064
-
1065
1136
  sym_id = ID2SYM(rb_intern("id"));
1066
1137
  sym_version = ID2SYM(rb_intern("version"));
1067
1138
  sym_async = ID2SYM(rb_intern("async"));
@@ -1071,6 +1142,7 @@ void init_mysql2_client() {
1071
1142
  sym_stream = ID2SYM(rb_intern("stream"));
1072
1143
 
1073
1144
  intern_merge = rb_intern("merge");
1145
+ intern_merge_bang = rb_intern("merge!");
1074
1146
  intern_error_number_eql = rb_intern("error_number=");
1075
1147
  intern_sql_state_eql = rb_intern("sql_state=");
1076
1148