mysql2 0.3.18 → 0.3.21

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 791bc0352c6464ca1765498b0babcedfad3c284e
4
- data.tar.gz: 08b44b761494ec18a0c9903fcb67bfe61718b77b
3
+ metadata.gz: 0e3404975106474ef92ef68d239b4c69901a380e
4
+ data.tar.gz: 77464b6c2940d1b8be408918678f4a6abb47c95f
5
5
  SHA512:
6
- metadata.gz: 5554897f395a4fcd71e26612ef895da5d3e1d528ef29604380974950f7216783bf7636197d04228c39b471a51863f75c56e9140e05bb79410e1582c64842d0dc
7
- data.tar.gz: afad060a7a899d69b75ca2c44aa69a07c743984fc6897cce825c6d9ec3269bbb3733671243afe7fb33a615e61e4aa8c7b9e7863fa18289578ab29abc8409e2e8
6
+ metadata.gz: e4e545f707900e4338c9965d068d81260b63cf3d7501926b5d2bce98415a1f589d88a541b256dc81f2e8519869103894303357f44dbc14b132fb3cfeca0d0f1d
7
+ data.tar.gz: 0e3d0943c65f739827fd394e471fa30e04a9c0a9499ed896e944f1b513de4c4c066b0c8e168d4bf66ebbc6905b0df9ffe7fe904094ff49ebff29abdb5c6c6ffc
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Brian Lopez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/ext/mysql2/client.c CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  VALUE cMysql2Client;
18
18
  extern VALUE mMysql2, cMysql2Error;
19
- static VALUE sym_id, sym_version, sym_async, sym_symbolize_keys, sym_as, sym_array, sym_stream;
19
+ static VALUE sym_id, sym_version, sym_header_version, sym_async, sym_symbolize_keys, sym_as, sym_array, sym_stream;
20
20
  static ID intern_merge, intern_merge_bang, intern_error_number_eql, intern_sql_state_eql;
21
21
 
22
22
  #ifndef HAVE_RB_HASH_DUP
@@ -182,23 +182,31 @@ static void *nogvl_connect(void *ptr) {
182
182
  */
183
183
  static VALUE invalidate_fd(int clientfd)
184
184
  {
185
- #ifdef SOCK_CLOEXEC
185
+ #ifdef O_CLOEXEC
186
186
  /* Atomically set CLOEXEC on the new FD in case another thread forks */
187
187
  int sockfd = open("/dev/null", O_RDWR | O_CLOEXEC);
188
- if (sockfd < 0) {
189
- /* Maybe SOCK_CLOEXEC is defined but not available on this kernel */
190
- int sockfd = open("/dev/null", O_RDWR);
191
- fcntl(sockfd, F_SETFD, FD_CLOEXEC);
192
- }
193
188
  #else
194
- /* Well we don't have SOCK_CLOEXEC, so just set FD_CLOEXEC quickly */
195
- int sockfd = open("/dev/null", O_RDWR);
196
- fcntl(sockfd, F_SETFD, FD_CLOEXEC);
189
+ /* Well we don't have O_CLOEXEC, trigger the fallback code below */
190
+ int sockfd = -1;
197
191
  #endif
198
192
 
199
193
  if (sockfd < 0) {
200
- /*
201
- * Cannot raise here, because one or both of the following may be true:
194
+ /* Either O_CLOEXEC wasn't defined at compile time, or it was defined at
195
+ * compile time, but isn't available at run-time. So we'll just be quick
196
+ * about setting FD_CLOEXEC now.
197
+ */
198
+ int flags;
199
+ sockfd = open("/dev/null", O_RDWR);
200
+ flags = fcntl(sockfd, F_GETFD);
201
+ /* Do the flags dance in case there are more defined flags in the future */
202
+ if (flags != -1) {
203
+ flags |= FD_CLOEXEC;
204
+ fcntl(sockfd, F_SETFD, flags);
205
+ }
206
+ }
207
+
208
+ if (sockfd < 0) {
209
+ /* Cannot raise here, because one or both of the following may be true:
202
210
  * a) we have no GVL (in C Ruby)
203
211
  * b) are running as a GC finalizer
204
212
  */
@@ -287,7 +295,7 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
287
295
  oldLen = RSTRING_LEN(str);
288
296
  newStr = xmalloc(oldLen*2+1);
289
297
 
290
- newLen = mysql_escape_string((char *)newStr, StringValuePtr(str), oldLen);
298
+ newLen = mysql_escape_string((char *)newStr, RSTRING_PTR(str), oldLen);
291
299
  if (newLen == oldLen) {
292
300
  /* no need to return a new ruby string if nothing changed */
293
301
  xfree(newStr);
@@ -337,13 +345,13 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
337
345
  VALUE rv;
338
346
  GET_CLIENT(self);
339
347
 
340
- args.host = NIL_P(host) ? NULL : StringValuePtr(host);
341
- args.unix_socket = NIL_P(socket) ? NULL : StringValuePtr(socket);
342
- args.port = NIL_P(port) ? 0 : NUM2INT(port);
343
- args.user = NIL_P(user) ? NULL : StringValuePtr(user);
344
- args.passwd = NIL_P(pass) ? NULL : StringValuePtr(pass);
345
- args.db = NIL_P(database) ? NULL : StringValuePtr(database);
346
- args.mysql = wrapper->client;
348
+ args.host = NIL_P(host) ? NULL : StringValueCStr(host);
349
+ args.unix_socket = NIL_P(socket) ? NULL : StringValueCStr(socket);
350
+ args.port = NIL_P(port) ? 0 : NUM2INT(port);
351
+ args.user = NIL_P(user) ? NULL : StringValueCStr(user);
352
+ args.passwd = NIL_P(pass) ? NULL : StringValueCStr(pass);
353
+ args.db = NIL_P(database) ? NULL : StringValueCStr(database);
354
+ args.mysql = wrapper->client;
347
355
  args.client_flag = NUM2ULONG(flags);
348
356
 
349
357
  if (wrapper->connect_timeout)
@@ -634,42 +642,29 @@ static VALUE rb_mysql_client_abandon_results(VALUE self) {
634
642
  * Query the database with +sql+, with optional +options+. For the possible
635
643
  * options, see @@default_query_options on the Mysql2::Client class.
636
644
  */
637
- static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
645
+ static VALUE rb_query(VALUE self, VALUE sql, VALUE current) {
638
646
  #ifndef _WIN32
639
647
  struct async_query_args async_args;
640
648
  #endif
641
649
  struct nogvl_send_query_args args;
642
- int async = 0;
643
- VALUE opts, current;
644
650
  VALUE thread_current = rb_thread_current();
645
- #ifdef HAVE_RUBY_ENCODING_H
646
- rb_encoding *conn_enc;
647
- #endif
648
651
  GET_CLIENT(self);
649
652
 
650
653
  REQUIRE_CONNECTED(wrapper);
651
654
  args.mysql = wrapper->client;
652
655
 
653
- current = rb_hash_dup(rb_iv_get(self, "@query_options"));
654
656
  RB_GC_GUARD(current);
655
657
  Check_Type(current, T_HASH);
656
658
  rb_iv_set(self, "@current_query_options", current);
657
659
 
658
- if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
659
- rb_funcall(current, intern_merge_bang, 1, opts);
660
-
661
- if (rb_hash_aref(current, sym_async) == Qtrue) {
662
- async = 1;
663
- }
664
- }
665
-
666
- Check_Type(args.sql, T_STRING);
660
+ Check_Type(sql, T_STRING);
667
661
  #ifdef HAVE_RUBY_ENCODING_H
668
- conn_enc = rb_to_encoding(wrapper->encoding);
669
662
  /* ensure the string is in the encoding the connection is expecting */
670
- args.sql = rb_str_export_to_enc(args.sql, conn_enc);
663
+ args.sql = rb_str_export_to_enc(sql, rb_to_encoding(wrapper->encoding));
664
+ #else
665
+ args.sql = sql;
671
666
  #endif
672
- args.sql_ptr = StringValuePtr(args.sql);
667
+ args.sql_ptr = RSTRING_PTR(args.sql);
673
668
  args.sql_len = RSTRING_LEN(args.sql);
674
669
 
675
670
  /* see if this connection is still waiting on a result from a previous query */
@@ -691,15 +686,15 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
691
686
  #ifndef _WIN32
692
687
  rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);
693
688
 
694
- if (!async) {
689
+ if (rb_hash_aref(current, sym_async) == Qtrue) {
690
+ return Qnil;
691
+ } else {
695
692
  async_args.fd = wrapper->client->net.fd;
696
693
  async_args.self = self;
697
694
 
698
695
  rb_rescue2(do_query, (VALUE)&async_args, disconnect_and_raise, self, rb_eException, (VALUE)0);
699
696
 
700
697
  return rb_mysql_client_async_result(self);
701
- } else {
702
- return Qnil;
703
698
  }
704
699
  #else
705
700
  do_send_query(&args);
@@ -736,9 +731,14 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
736
731
  oldLen = RSTRING_LEN(str);
737
732
  newStr = xmalloc(oldLen*2+1);
738
733
 
739
- newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, StringValuePtr(str), oldLen);
734
+ newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, RSTRING_PTR(str), oldLen);
740
735
  if (newLen == oldLen) {
741
736
  /* no need to return a new ruby string if nothing changed */
737
+ #ifdef HAVE_RUBY_ENCODING_H
738
+ if (default_internal_enc) {
739
+ str = rb_str_export_to_enc(str, default_internal_enc);
740
+ }
741
+ #endif
742
742
  xfree(newStr);
743
743
  return str;
744
744
  } else {
@@ -800,17 +800,17 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
800
800
  break;
801
801
 
802
802
  case MYSQL_READ_DEFAULT_FILE:
803
- charval = (const char *)StringValuePtr(value);
803
+ charval = (const char *)StringValueCStr(value);
804
804
  retval = charval;
805
805
  break;
806
806
 
807
807
  case MYSQL_READ_DEFAULT_GROUP:
808
- charval = (const char *)StringValuePtr(value);
808
+ charval = (const char *)StringValueCStr(value);
809
809
  retval = charval;
810
810
  break;
811
811
 
812
812
  case MYSQL_INIT_COMMAND:
813
- charval = (const char *)StringValuePtr(value);
813
+ charval = (const char *)StringValueCStr(value);
814
814
  retval = charval;
815
815
  break;
816
816
 
@@ -843,30 +843,23 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
843
843
  *
844
844
  * Returns a string that represents the client library version.
845
845
  */
846
- static VALUE rb_mysql_client_info(VALUE self) {
847
- VALUE version, client_info;
848
- #ifdef HAVE_RUBY_ENCODING_H
849
- rb_encoding *default_internal_enc;
850
- rb_encoding *conn_enc;
851
- GET_CLIENT(self);
852
- #endif
853
- version = rb_hash_new();
846
+ static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE klass) {
847
+ VALUE version_info, version, header_version;
848
+ version_info = rb_hash_new();
854
849
 
855
- #ifdef HAVE_RUBY_ENCODING_H
856
- default_internal_enc = rb_default_internal_encoding();
857
- conn_enc = rb_to_encoding(wrapper->encoding);
858
- #endif
850
+ version = rb_str_new2(mysql_get_client_info());
851
+ header_version = rb_str_new2(MYSQL_LINK_VERSION);
859
852
 
860
- rb_hash_aset(version, sym_id, LONG2NUM(mysql_get_client_version()));
861
- client_info = rb_str_new2(mysql_get_client_info());
862
853
  #ifdef HAVE_RUBY_ENCODING_H
863
- rb_enc_associate(client_info, conn_enc);
864
- if (default_internal_enc) {
865
- client_info = rb_str_export_to_enc(client_info, default_internal_enc);
866
- }
854
+ rb_enc_associate(version, rb_usascii_encoding());
855
+ rb_enc_associate(header_version, rb_usascii_encoding());
867
856
  #endif
868
- rb_hash_aset(version, sym_version, client_info);
869
- return version;
857
+
858
+ rb_hash_aset(version_info, sym_id, LONG2NUM(mysql_get_client_version()));
859
+ rb_hash_aset(version_info, sym_version, version);
860
+ rb_hash_aset(version_info, sym_header_version, header_version);
861
+
862
+ return version_info;
870
863
  }
871
864
 
872
865
  /* call-seq:
@@ -907,14 +900,10 @@ static VALUE rb_mysql_client_server_info(VALUE self) {
907
900
  * Return the file descriptor number for this client.
908
901
  */
909
902
  static VALUE rb_mysql_client_socket(VALUE self) {
910
- GET_CLIENT(self);
911
903
  #ifndef _WIN32
912
- {
913
- int fd_set_fd;
914
- REQUIRE_CONNECTED(wrapper);
915
- fd_set_fd = wrapper->client->net.fd;
916
- return INT2NUM(fd_set_fd);
917
- }
904
+ GET_CLIENT(self);
905
+ REQUIRE_CONNECTED(wrapper);
906
+ return INT2NUM(wrapper->client->net.fd);
918
907
  #else
919
908
  rb_raise(cMysql2Error, "Raw access to the mysql file descriptor isn't supported on Windows");
920
909
  #endif
@@ -987,7 +976,7 @@ static VALUE rb_mysql_client_select_db(VALUE self, VALUE db)
987
976
  REQUIRE_CONNECTED(wrapper);
988
977
 
989
978
  args.mysql = wrapper->client;
990
- args.db = StringValuePtr(db);
979
+ args.db = StringValueCStr(db);
991
980
 
992
981
  if (rb_thread_call_without_gvl(nogvl_select_db, &args, RUBY_UBF_IO, 0) == Qfalse)
993
982
  rb_raise_mysql2_error(wrapper);
@@ -1183,11 +1172,11 @@ static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE
1183
1172
  GET_CLIENT(self);
1184
1173
 
1185
1174
  mysql_ssl_set(wrapper->client,
1186
- NIL_P(key) ? NULL : StringValuePtr(key),
1187
- NIL_P(cert) ? NULL : StringValuePtr(cert),
1188
- NIL_P(ca) ? NULL : StringValuePtr(ca),
1189
- NIL_P(capath) ? NULL : StringValuePtr(capath),
1190
- NIL_P(cipher) ? NULL : StringValuePtr(cipher));
1175
+ NIL_P(key) ? NULL : StringValueCStr(key),
1176
+ NIL_P(cert) ? NULL : StringValueCStr(cert),
1177
+ NIL_P(ca) ? NULL : StringValueCStr(ca),
1178
+ NIL_P(capath) ? NULL : StringValueCStr(capath),
1179
+ NIL_P(cipher) ? NULL : StringValueCStr(cipher));
1191
1180
 
1192
1181
  return self;
1193
1182
  }
@@ -1254,12 +1243,11 @@ void init_mysql2_client() {
1254
1243
  rb_define_alloc_func(cMysql2Client, allocate);
1255
1244
 
1256
1245
  rb_define_singleton_method(cMysql2Client, "escape", rb_mysql_client_escape, 1);
1246
+ rb_define_singleton_method(cMysql2Client, "info", rb_mysql_client_info, 0);
1257
1247
 
1258
1248
  rb_define_method(cMysql2Client, "close", rb_mysql_client_close, 0);
1259
- rb_define_method(cMysql2Client, "query", rb_mysql_client_query, -1);
1260
1249
  rb_define_method(cMysql2Client, "abandon_results!", rb_mysql_client_abandon_results, 0);
1261
1250
  rb_define_method(cMysql2Client, "escape", rb_mysql_client_real_escape, 1);
1262
- rb_define_method(cMysql2Client, "info", rb_mysql_client_info, 0);
1263
1251
  rb_define_method(cMysql2Client, "server_info", rb_mysql_client_server_info, 0);
1264
1252
  rb_define_method(cMysql2Client, "socket", rb_mysql_client_socket, 0);
1265
1253
  rb_define_method(cMysql2Client, "async_result", rb_mysql_client_async_result, 0);
@@ -1290,9 +1278,11 @@ void init_mysql2_client() {
1290
1278
  rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
1291
1279
  rb_define_private_method(cMysql2Client, "initialize_ext", initialize_ext, 0);
1292
1280
  rb_define_private_method(cMysql2Client, "connect", rb_connect, 7);
1281
+ rb_define_private_method(cMysql2Client, "_query", rb_query, 2);
1293
1282
 
1294
1283
  sym_id = ID2SYM(rb_intern("id"));
1295
1284
  sym_version = ID2SYM(rb_intern("version"));
1285
+ sym_header_version = ID2SYM(rb_intern("header_version"));
1296
1286
  sym_async = ID2SYM(rb_intern("async"));
1297
1287
  sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
1298
1288
  sym_as = ID2SYM(rb_intern("as"));
@@ -2,7 +2,13 @@
2
2
  require 'mkmf'
3
3
 
4
4
  def asplode lib
5
- abort "-----\n#{lib} is missing. please check your installation of mysql and try again.\n-----"
5
+ if RUBY_PLATFORM =~ /mingw|mswin/
6
+ abort "-----\n#{lib} is missing. Check your installation of MySQL or Connector/C, and try again.\n-----"
7
+ elsif RUBY_PLATFORM =~ /darwin/
8
+ abort "-----\n#{lib} is missing. You may need to 'brew install mysql' or 'port install mysql', and try again.\n-----"
9
+ else
10
+ abort "-----\n#{lib} is missing. You may need to 'apt-get install libmysqlclient-dev' or 'yum install mysql-devel', and try again.\n-----"
11
+ end
6
12
  end
7
13
 
8
14
  # 2.0-only
@@ -29,7 +35,7 @@ dirs = ENV['PATH'].split(File::PATH_SEPARATOR) + %w[
29
35
  /usr/local/lib/mysql5*
30
36
  ].map{|dir| "#{dir}/bin" }
31
37
 
32
- GLOB = "{#{dirs.join(',')}}/{mysql_config,mysql_config5}"
38
+ GLOB = "{#{dirs.join(',')}}/{mysql_config,mysql_config5,mariadb_config}"
33
39
 
34
40
  # If the user has provided a --with-mysql-dir argument, we must respect it or fail.
35
41
  inc, lib = dir_config('mysql')
@@ -66,11 +72,22 @@ elsif mc = (with_config('mysql-config') || Dir[GLOB].first)
66
72
  rpath_dir = libs
67
73
  else
68
74
  inc, lib = dir_config('mysql', '/usr/local')
69
- libs = ['m', 'z', 'socket', 'nsl', 'mygcc']
70
- while not find_library('mysqlclient', 'mysql_query', lib, "#{lib}/mysql") do
71
- exit 1 if libs.empty?
72
- have_library(libs.shift)
75
+ unless find_library('mysqlclient', 'mysql_query', lib, "#{lib}/mysql")
76
+ found = false
77
+ # For some systems and some versions of libmysqlclient, there were extra
78
+ # libraries needed to link. Try each typical extra library, add it to the
79
+ # global compile flags, and see if that allows us to link libmysqlclient.
80
+ warn "-----\nlibmysqlclient is missing. Trying again with extra runtime libraries...\n-----"
81
+
82
+ %w{ m z socket nsl mygcc }.each do |extra_lib|
83
+ if have_library(extra_lib) && find_library('mysqlclient', 'mysql_query', lib, "#{lib}/mysql")
84
+ found = true
85
+ break
86
+ end
87
+ end
88
+ asplode('libmysqlclient') unless found
73
89
  end
90
+
74
91
  rpath_dir = lib
75
92
  end
76
93
 
data/ext/mysql2/result.c CHANGED
@@ -50,6 +50,10 @@ static rb_encoding *binaryEncoding;
50
50
  #define MYSQL2_MIN_TIME 62171150401ULL
51
51
  #endif
52
52
 
53
+ #define GET_RESULT(obj) \
54
+ mysql2_result_wrapper *wrapper; \
55
+ Data_Get_Struct(self, mysql2_result_wrapper, wrapper);
56
+
53
57
  static VALUE cMysql2Result;
54
58
  static VALUE cBigDecimal, cDate, cDateTime;
55
59
  static VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month, opt_utc_offset;
@@ -103,9 +107,8 @@ static void *nogvl_fetch_row(void *ptr) {
103
107
  }
104
108
 
105
109
  static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int symbolize_keys) {
106
- mysql2_result_wrapper * wrapper;
107
110
  VALUE rb_field;
108
- GetMysql2Result(self, wrapper);
111
+ GET_RESULT(self);
109
112
 
110
113
  if (wrapper->fields == Qnil) {
111
114
  wrapper->numberOfFields = mysql_num_fields(wrapper->result);
@@ -193,7 +196,6 @@ static unsigned int msec_char_to_uint(char *msec_char, size_t len)
193
196
 
194
197
  static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezone, int symbolizeKeys, int asArray, int castBool, int cast, MYSQL_FIELD * fields) {
195
198
  VALUE rowVal;
196
- mysql2_result_wrapper * wrapper;
197
199
  MYSQL_ROW row;
198
200
  unsigned int i = 0;
199
201
  unsigned long * fieldLengths;
@@ -202,7 +204,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
202
204
  rb_encoding *default_internal_enc;
203
205
  rb_encoding *conn_enc;
204
206
  #endif
205
- GetMysql2Result(self, wrapper);
207
+ GET_RESULT(self);
206
208
 
207
209
  #ifdef HAVE_RUBY_ENCODING_H
208
210
  default_internal_enc = rb_default_internal_encoding();
@@ -413,12 +415,11 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
413
415
  }
414
416
 
415
417
  static VALUE rb_mysql_result_fetch_fields(VALUE self) {
416
- mysql2_result_wrapper * wrapper;
417
418
  unsigned int i = 0;
418
419
  short int symbolizeKeys = 0;
419
420
  VALUE defaults;
420
421
 
421
- GetMysql2Result(self, wrapper);
422
+ GET_RESULT(self);
422
423
 
423
424
  defaults = rb_iv_get(self, "@query_options");
424
425
  Check_Type(defaults, T_HASH);
@@ -443,13 +444,12 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
443
444
  static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
444
445
  VALUE defaults, opts, block;
445
446
  ID db_timezone, app_timezone, dbTz, appTz;
446
- mysql2_result_wrapper * wrapper;
447
447
  unsigned long i;
448
448
  const char * errstr;
449
- int symbolizeKeys = 0, asArray = 0, castBool = 0, cacheRows = 1, cast = 1, streaming = 0;
449
+ int symbolizeKeys, asArray, castBool, cacheRows, cast;
450
450
  MYSQL_FIELD * fields = NULL;
451
451
 
452
- GetMysql2Result(self, wrapper);
452
+ GET_RESULT(self);
453
453
 
454
454
  defaults = rb_iv_get(self, "@query_options");
455
455
  Check_Type(defaults, T_HASH);
@@ -459,32 +459,14 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
459
459
  opts = defaults;
460
460
  }
461
461
 
462
- if (rb_hash_aref(opts, sym_symbolize_keys) == Qtrue) {
463
- symbolizeKeys = 1;
464
- }
465
-
466
- if (rb_hash_aref(opts, sym_as) == sym_array) {
467
- asArray = 1;
468
- }
469
-
470
- if (rb_hash_aref(opts, sym_cast_booleans) == Qtrue) {
471
- castBool = 1;
472
- }
473
-
474
- if (rb_hash_aref(opts, sym_cache_rows) == Qfalse) {
475
- cacheRows = 0;
476
- }
477
-
478
- if (rb_hash_aref(opts, sym_cast) == Qfalse) {
479
- cast = 0;
480
- }
462
+ symbolizeKeys = RTEST(rb_hash_aref(opts, sym_symbolize_keys));
463
+ asArray = rb_hash_aref(opts, sym_as) == sym_array;
464
+ castBool = RTEST(rb_hash_aref(opts, sym_cast_booleans));
465
+ cacheRows = RTEST(rb_hash_aref(opts, sym_cache_rows));
466
+ cast = RTEST(rb_hash_aref(opts, sym_cast));
481
467
 
482
- if (rb_hash_aref(opts, sym_stream) == Qtrue) {
483
- streaming = 1;
484
- }
485
-
486
- if (streaming && cacheRows) {
487
- rb_warn("cacheRows is ignored if streaming is true");
468
+ if (wrapper->is_streaming && cacheRows) {
469
+ rb_warn(":cache_rows is ignored if :stream is true");
488
470
  }
489
471
 
490
472
  dbTz = rb_hash_aref(opts, sym_database_timezone);
@@ -508,23 +490,12 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
508
490
  app_timezone = Qnil;
509
491
  }
510
492
 
511
- if (wrapper->lastRowProcessed == 0) {
512
- if (streaming) {
513
- /* We can't get number of rows if we're streaming, */
514
- /* until we've finished fetching all rows */
515
- wrapper->numberOfRows = 0;
493
+ if (wrapper->is_streaming) {
494
+ /* When streaming, we will only yield rows, not return them. */
495
+ if (wrapper->rows == Qnil) {
516
496
  wrapper->rows = rb_ary_new();
517
- } else {
518
- wrapper->numberOfRows = mysql_num_rows(wrapper->result);
519
- if (wrapper->numberOfRows == 0) {
520
- wrapper->rows = rb_ary_new();
521
- return wrapper->rows;
522
- }
523
- wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
524
497
  }
525
- }
526
498
 
527
- if (streaming) {
528
499
  if (!wrapper->streamingComplete) {
529
500
  VALUE row;
530
501
 
@@ -532,16 +503,15 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
532
503
 
533
504
  do {
534
505
  row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool, cast, fields);
535
-
536
- if (block != Qnil && row != Qnil) {
537
- rb_yield(row);
538
- wrapper->lastRowProcessed++;
506
+ if (row != Qnil) {
507
+ wrapper->numberOfRows++;
508
+ if (block != Qnil) {
509
+ rb_yield(row);
510
+ }
539
511
  }
540
512
  } while(row != Qnil);
541
513
 
542
514
  rb_mysql_result_free_result(wrapper);
543
-
544
- wrapper->numberOfRows = wrapper->lastRowProcessed;
545
515
  wrapper->streamingComplete = 1;
546
516
 
547
517
  // Check for errors, the connection might have gone out from under us
@@ -554,6 +524,19 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
554
524
  rb_raise(cMysql2Error, "You have already fetched all the rows for this query and streaming is true. (to reiterate you must requery).");
555
525
  }
556
526
  } else {
527
+ if (wrapper->lastRowProcessed == 0) {
528
+ wrapper->numberOfRows = mysql_num_rows(wrapper->result);
529
+ if (wrapper->numberOfRows == 0) {
530
+ wrapper->rows = rb_ary_new();
531
+ return wrapper->rows;
532
+ }
533
+ wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
534
+ } else if (!cacheRows && wrapper->lastRowProcessed == wrapper->numberOfRows) {
535
+ mysql_data_seek(wrapper->result, 0);
536
+ wrapper->lastRowProcessed = 0;
537
+ wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
538
+ }
539
+
557
540
  if (cacheRows && wrapper->lastRowProcessed == wrapper->numberOfRows) {
558
541
  /* we've already read the entire dataset from the C result into our */
559
542
  /* internal array. Lets hand that over to the user since it's ready to go */
@@ -579,7 +562,9 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
579
562
 
580
563
  if (row == Qnil) {
581
564
  /* we don't need the mysql C dataset around anymore, peace it */
582
- rb_mysql_result_free_result(wrapper);
565
+ if (cacheRows) {
566
+ rb_mysql_result_free_result(wrapper);
567
+ }
583
568
  return Qnil;
584
569
  }
585
570
 
@@ -587,7 +572,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
587
572
  rb_yield(row);
588
573
  }
589
574
  }
590
- if (wrapper->lastRowProcessed == wrapper->numberOfRows) {
575
+ if (wrapper->lastRowProcessed == wrapper->numberOfRows && cacheRows) {
591
576
  /* we don't need the mysql C dataset around anymore, peace it */
592
577
  rb_mysql_result_free_result(wrapper);
593
578
  }
@@ -598,17 +583,19 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
598
583
  }
599
584
 
600
585
  static VALUE rb_mysql_result_count(VALUE self) {
601
- mysql2_result_wrapper *wrapper;
586
+ GET_RESULT(self);
587
+
588
+ if (wrapper->is_streaming) {
589
+ /* This is an unsigned long per result.h */
590
+ return ULONG2NUM(wrapper->numberOfRows);
591
+ }
602
592
 
603
- GetMysql2Result(self, wrapper);
604
593
  if (wrapper->resultFreed) {
605
- if (wrapper->streamingComplete){
606
- return LONG2NUM(wrapper->numberOfRows);
607
- } else {
608
- return LONG2NUM(RARRAY_LEN(wrapper->rows));
609
- }
594
+ /* Ruby arrays have platform signed long length */
595
+ return LONG2NUM(RARRAY_LEN(wrapper->rows));
610
596
  } else {
611
- return INT2FIX(mysql_num_rows(wrapper->result));
597
+ /* MySQL returns an unsigned 64-bit long here */
598
+ return ULL2NUM(mysql_num_rows(wrapper->result));
612
599
  }
613
600
  }
614
601
 
@@ -616,6 +603,7 @@ static VALUE rb_mysql_result_count(VALUE self) {
616
603
  VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_RES *r) {
617
604
  VALUE obj;
618
605
  mysql2_result_wrapper * wrapper;
606
+
619
607
  obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper);
620
608
  wrapper->numberOfFields = 0;
621
609
  wrapper->numberOfRows = 0;
@@ -634,6 +622,10 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
634
622
 
635
623
  rb_iv_set(obj, "@query_options", options);
636
624
 
625
+ /* Options that cannot be changed in results.each(...) { |row| }
626
+ * should be processed here. */
627
+ wrapper->is_streaming = (rb_hash_aref(options, sym_stream) == Qtrue ? 1 : 0);
628
+
637
629
  return obj;
638
630
  }
639
631
 
data/ext/mysql2/result.h CHANGED
@@ -12,12 +12,11 @@ typedef struct {
12
12
  unsigned int numberOfFields;
13
13
  unsigned long numberOfRows;
14
14
  unsigned long lastRowProcessed;
15
+ char is_streaming;
15
16
  char streamingComplete;
16
17
  char resultFreed;
17
18
  MYSQL_RES *result;
18
19
  mysql_client_wrapper *client_wrapper;
19
20
  } mysql2_result_wrapper;
20
21
 
21
- #define GetMysql2Result(obj, sval) (sval = (mysql2_result_wrapper*)DATA_PTR(obj));
22
-
23
22
  #endif
data/lib/mysql2/client.rb CHANGED
@@ -74,6 +74,18 @@ module Mysql2
74
74
  @@default_query_options
75
75
  end
76
76
 
77
+ if Thread.respond_to?(:handle_interrupt)
78
+ def query(sql, options = {})
79
+ Thread.handle_interrupt(::Mysql2::Util::TimeoutError => :never) do
80
+ _query(sql, @query_options.merge(options))
81
+ end
82
+ end
83
+ else
84
+ def query(sql, options = {})
85
+ _query(sql, @query_options.merge(options))
86
+ end
87
+ end
88
+
77
89
  def query_info
78
90
  info = query_info_string
79
91
  return {} unless info
@@ -82,6 +94,10 @@ module Mysql2
82
94
  info_hash
83
95
  end
84
96
 
97
+ def info
98
+ self.class.info
99
+ end
100
+
85
101
  private
86
102
  def self.local_offset
87
103
  ::Time.local(2010).utc_offset.to_r / 86400
data/lib/mysql2/error.rb CHANGED
@@ -30,7 +30,7 @@ module Mysql2
30
30
  # variable.
31
31
  #
32
32
  # See http://dev.mysql.com/doc/refman/5.5/en/charset-errors.html for
33
- # more contetx.
33
+ # more context.
34
34
  #
35
35
  # Before MySQL 5.5 error message template strings are in whatever encoding
36
36
  # is associated with the error message language.
@@ -1,3 +1,3 @@
1
1
  module Mysql2
2
- VERSION = "0.3.18"
2
+ VERSION = "0.3.21"
3
3
  end
data/lib/mysql2.rb CHANGED
@@ -61,4 +61,22 @@ module Mysql2::Util
61
61
  Hash[hash.map { |k,v| [k.to_sym, v] }]
62
62
  end
63
63
 
64
+ #
65
+ # In Mysql2::Client#query and Mysql2::Statement#execute,
66
+ # Thread#handle_interrupt is used to prevent Timeout#timeout
67
+ # from interrupting query execution.
68
+ #
69
+ # Timeout::ExitException was removed in Ruby 2.3.0, 2.2.3, and 2.1.8,
70
+ # but is present in earlier 2.1.x and 2.2.x, so we provide a shim.
71
+ #
72
+ if Thread.respond_to?(:handle_interrupt)
73
+ require 'timeout'
74
+ # rubocop:disable Style/ConstantName
75
+ TimeoutError = if defined?(::Timeout::ExitException)
76
+ ::Timeout::ExitException
77
+ else
78
+ ::Timeout::Error
79
+ end
80
+ end
81
+
64
82
  end
@@ -66,12 +66,13 @@ describe Mysql2::Client do
66
66
  end
67
67
  end
68
68
  client = klient.new
69
- (client.connect_args.last[6] & (Mysql2::Client::REMEMBER_OPTIONS |
70
- Mysql2::Client::LONG_PASSWORD |
71
- Mysql2::Client::LONG_FLAG |
72
- Mysql2::Client::TRANSACTIONS |
73
- Mysql2::Client::PROTOCOL_41 |
74
- Mysql2::Client::SECURE_CONNECTION)).should be_true
69
+ client_flags = Mysql2::Client::REMEMBER_OPTIONS |
70
+ Mysql2::Client::LONG_PASSWORD |
71
+ Mysql2::Client::LONG_FLAG |
72
+ Mysql2::Client::TRANSACTIONS |
73
+ Mysql2::Client::PROTOCOL_41 |
74
+ Mysql2::Client::SECURE_CONNECTION
75
+ client.connect_args.last[6].should eql(client_flags)
75
76
  end
76
77
 
77
78
  it "should execute init command" do
@@ -461,59 +462,39 @@ describe Mysql2::Client do
461
462
  }.should raise_error(Mysql2::Error)
462
463
  end
463
464
 
464
- it "should close the connection when an exception is raised" do
465
- begin
466
- Timeout.timeout(1, Timeout::Error) do
467
- @client.query("SELECT sleep(2)")
468
- end
469
- rescue Timeout::Error
470
- end
465
+ it 'should be impervious to connection-corrupting timeouts in #query' do
466
+ pending('`Thread.handle_interrupt` is not defined') unless Thread.respond_to?(:handle_interrupt)
467
+ # attempt to break the connection
468
+ expect { Timeout.timeout(0.1) { @client.query('SELECT SLEEP(1)') } }.to raise_error(Timeout::Error)
471
469
 
472
- lambda {
473
- @client.query("SELECT 1")
474
- }.should raise_error(Mysql2::Error, 'closed MySQL connection')
470
+ # expect the connection to not be broken
471
+ expect { @client.query('SELECT 1') }.to_not raise_error
475
472
  end
476
473
 
477
- it "should handle Timeouts without leaving the connection hanging if reconnect is true" do
478
- client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:reconnect => true))
479
- begin
480
- Timeout.timeout(1, Timeout::Error) do
481
- client.query("SELECT sleep(2)")
482
- end
483
- rescue Timeout::Error
474
+ context 'when a non-standard exception class is raised' do
475
+ it "should close the connection when an exception is raised" do
476
+ expect { Timeout.timeout(0.1, ArgumentError) { @client.query('SELECT SLEEP(1)') } }.to raise_error(ArgumentError)
477
+ expect { @client.query('SELECT 1') }.to raise_error(Mysql2::Error, 'closed MySQL connection')
484
478
  end
485
479
 
486
- lambda {
487
- client.query("SELECT 1")
488
- }.should_not raise_error(Mysql2::Error)
489
- end
480
+ it "should handle Timeouts without leaving the connection hanging if reconnect is true" do
481
+ client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:reconnect => true))
490
482
 
491
- it "should handle Timeouts without leaving the connection hanging if reconnect is set to true after construction true" do
492
- client = Mysql2::Client.new(DatabaseCredentials['root'])
493
- begin
494
- Timeout.timeout(1, Timeout::Error) do
495
- client.query("SELECT sleep(2)")
496
- end
497
- rescue Timeout::Error
483
+ expect { Timeout.timeout(0.1, ArgumentError) { client.query('SELECT SLEEP(1)') } }.to raise_error(ArgumentError)
484
+ expect { client.query('SELECT 1') }.to_not raise_error
498
485
  end
499
486
 
500
- lambda {
501
- client.query("SELECT 1")
502
- }.should raise_error(Mysql2::Error)
487
+ it "should handle Timeouts without leaving the connection hanging if reconnect is set to true after construction true" do
488
+ client = Mysql2::Client.new(DatabaseCredentials['root'])
503
489
 
504
- client.reconnect = true
490
+ expect { Timeout.timeout(0.1, ArgumentError) { client.query('SELECT SLEEP(1)') } }.to raise_error(ArgumentError)
491
+ expect { client.query('SELECT 1') }.to raise_error(Mysql2::Error)
505
492
 
506
- begin
507
- Timeout.timeout(1, Timeout::Error) do
508
- client.query("SELECT sleep(2)")
509
- end
510
- rescue Timeout::Error
511
- end
512
-
513
- lambda {
514
- client.query("SELECT 1")
515
- }.should_not raise_error(Mysql2::Error)
493
+ client.reconnect = true
516
494
 
495
+ expect { Timeout.timeout(0.1, ArgumentError) { client.query('SELECT SLEEP(1)') } }.to raise_error(ArgumentError)
496
+ expect { client.query('SELECT 1') }.to_not raise_error
497
+ end
517
498
  end
518
499
 
519
500
  it "threaded queries should be supported" do
@@ -614,6 +595,21 @@ describe Mysql2::Client do
614
595
 
615
596
  @multi_client.more_results?.should be_false
616
597
  end
598
+
599
+ it "#more_results? should work with stored procedures" do
600
+ @multi_client.query("DROP PROCEDURE IF EXISTS test_proc")
601
+ @multi_client.query("CREATE PROCEDURE test_proc() BEGIN SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'; END")
602
+ @multi_client.query("CALL test_proc()").first.should eql({ 'set_1' => 1 })
603
+ @multi_client.more_results?.should be_true
604
+
605
+ @multi_client.next_result
606
+ @multi_client.store_result.first.should eql({ 'set_2' => 2 })
607
+
608
+ @multi_client.next_result
609
+ @multi_client.store_result.should be_nil # this is the result from CALL itself
610
+
611
+ @multi_client.more_results?.should be_false
612
+ end
617
613
  end
618
614
  end
619
615
 
@@ -700,6 +696,19 @@ describe Mysql2::Client do
700
696
  @client.escape ""
701
697
  }.should raise_error(Mysql2::Error)
702
698
  end
699
+
700
+ context 'when mysql encoding is not utf8' do
701
+ before { pending('Encoding is undefined') unless defined?(Encoding) }
702
+
703
+ let(:client) { Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "ujis")) }
704
+
705
+ it 'should return a internal encoding string if Encoding.default_internal is set' do
706
+ with_internal_encoding Encoding::UTF_8 do
707
+ client.escape("\u{30C6}\u{30B9}\u{30C8}").should eql("\u{30C6}\u{30B9}\u{30C8}")
708
+ client.escape("\u{30C6}'\u{30B9}\"\u{30C8}").should eql("\u{30C6}\\'\u{30B9}\\\"\u{30C8}")
709
+ end
710
+ end
711
+ end
703
712
  end
704
713
 
705
714
  it "should respond to #info" do
@@ -715,26 +724,21 @@ describe Mysql2::Client do
715
724
  info[:version].class.should eql(String)
716
725
  end
717
726
 
718
- if defined? Encoding
719
- context "strings returned by #info" do
720
- it "should default to the connection's encoding if Encoding.default_internal is nil" do
721
- with_internal_encoding nil do
722
- @client.info[:version].encoding.should eql(Encoding.find('utf-8'))
727
+ context "strings returned by #info" do
728
+ before { pending('Encoding is undefined') unless defined?(Encoding) }
723
729
 
724
- client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii'))
725
- client2.info[:version].encoding.should eql(Encoding.find('us-ascii'))
726
- end
727
- end
730
+ it "should be tagged as ascii" do
731
+ @client.info[:version].encoding.should eql(Encoding::US_ASCII)
732
+ @client.info[:header_version].encoding.should eql(Encoding::US_ASCII)
733
+ end
734
+ end
728
735
 
729
- it "should use Encoding.default_internal" do
730
- with_internal_encoding 'utf-8' do
731
- @client.info[:version].encoding.should eql(Encoding.default_internal)
732
- end
736
+ context "strings returned by .info" do
737
+ before { pending('Encoding is undefined') unless defined?(Encoding) }
733
738
 
734
- with_internal_encoding 'us-ascii' do
735
- @client.info[:version].encoding.should eql(Encoding.default_internal)
736
- end
737
- end
739
+ it "should be tagged as ascii" do
740
+ Mysql2::Client.info[:version].encoding.should eql(Encoding::US_ASCII)
741
+ Mysql2::Client.info[:header_version].encoding.should eql(Encoding::US_ASCII)
738
742
  end
739
743
  end
740
744
 
@@ -6,6 +6,14 @@ describe Mysql2::Result do
6
6
  @result = @client.query "SELECT 1"
7
7
  end
8
8
 
9
+ it "should raise a TypeError exception when it doesn't wrap a result set" do
10
+ r = Mysql2::Result.new
11
+ expect { r.count }.to raise_error(TypeError)
12
+ expect { r.fields }.to raise_error(TypeError)
13
+ expect { r.size }.to raise_error(TypeError)
14
+ expect { r.each }.to raise_error(TypeError)
15
+ end
16
+
9
17
  it "should have included Enumerable" do
10
18
  Mysql2::Result.ancestors.include?(Enumerable).should be_true
11
19
  end
@@ -70,6 +78,11 @@ describe Mysql2::Result do
70
78
  result.first.object_id.should_not eql(result.first.object_id)
71
79
  end
72
80
 
81
+ it "should be able to iterate a second time even if cache_rows is disabled" do
82
+ result = @client.query "SELECT 1 UNION SELECT 2", :cache_rows => false
83
+ result.to_a.should eql(result.to_a)
84
+ end
85
+
73
86
  it "should yield different value for #first if streaming" do
74
87
  result = @client.query "SELECT 1 UNION SELECT 2", :stream => true, :cache_rows => false
75
88
  result.first.should_not eql(result.first)
@@ -107,18 +120,19 @@ describe Mysql2::Result do
107
120
 
108
121
  context "streaming" do
109
122
  it "should maintain a count while streaming" do
110
- result = @client.query('SELECT 1')
111
-
112
- result.count.should eql(1)
123
+ result = @client.query('SELECT 1', :stream => true, :cache_rows => false)
124
+ result.count.should eql(0)
113
125
  result.each.to_a
114
126
  result.count.should eql(1)
115
127
  end
116
128
 
117
- it "should set the actual count of rows after streaming" do
118
- result = @client.query("SELECT * FROM mysql2_test", :stream => true, :cache_rows => false)
129
+ it "should retain the count when mixing first and each" do
130
+ result = @client.query("SELECT 1 UNION SELECT 2", :stream => true, :cache_rows => false)
119
131
  result.count.should eql(0)
120
- result.each {|r| }
132
+ result.first
121
133
  result.count.should eql(1)
134
+ result.each.to_a
135
+ result.count.should eql(2)
122
136
  end
123
137
 
124
138
  it "should not yield nil at the end of streaming" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mysql2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.18
4
+ version: 0.3.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Lopez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-17 00:00:00.000000000 Z
11
+ date: 2016-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -59,6 +59,7 @@ extensions:
59
59
  - ext/mysql2/extconf.rb
60
60
  extra_rdoc_files: []
61
61
  files:
62
+ - LICENSE
62
63
  - README.md
63
64
  - ext/mysql2/client.c
64
65
  - ext/mysql2/client.h
@@ -114,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
115
  version: '0'
115
116
  requirements: []
116
117
  rubyforge_project:
117
- rubygems_version: 2.0.14
118
+ rubygems_version: 2.0.14.1
118
119
  signing_key:
119
120
  specification_version: 4
120
121
  summary: A simple, fast Mysql library for Ruby, binding to libmysql