mysql2 0.5.4 → 0.5.6

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
  SHA256:
3
- metadata.gz: f387f841adc885eb4000a960ee34f475c7edab79e276d17ce8889f370bdcf387
4
- data.tar.gz: 0c8732c2a45ed8ac68aea92765daba5969f860f1fe5a95d44e89b76deae7108b
3
+ metadata.gz: d8e25b1a25080490b1bf04829d8f6616609391a094baa783d7da242342a4ff3b
4
+ data.tar.gz: 7dfab0d03b289b665807d21b29326b96711e5c1d3ae697e81f0e4ab7a5dd6280
5
5
  SHA512:
6
- metadata.gz: 8d6afb1b661525183075d14046630195bc79a5f945b92489d3daa0aeea8582e8d17a0fa9d1781fadeaaefaaeac567ead5ad7d0266e1fb9aa96076d26f1c03ad1
7
- data.tar.gz: 9b2202a06e36ca910a9648f71d8646e67a6e665153b3ac04dcd535cd768bb78942dd799893e205df841b0461aeb5810985704e18e4a045b540f2d272b11776cd
6
+ metadata.gz: 3709403d316832055596c96af2e260e3de9d181ba558f551f0d5fe0d89abfec0ea242f6c30228eac02284e1e7287cbd315933fadc517fab88a10d588c4f0d8b6
7
+ data.tar.gz: 63c17fa1c273cefa454ea7f6cc0860014514e4c899ceb1bd856271cd238938a4d0fb263118eb64dde0a9568905d6410110fbe3b8359bff3fab8314607de6dd50
data/README.md CHANGED
@@ -65,6 +65,11 @@ This may be needed if you deploy to a system where these libraries
65
65
  are located somewhere different than on your build system.
66
66
  This overrides any rpath calculated by default or by the options above.
67
67
 
68
+ * `--with-openssl-dir[=/path/to/openssl]` - Specify the directory where OpenSSL
69
+ is installed. In most cases, the Ruby runtime and MySQL client libraries will
70
+ link against a system-installed OpenSSL library and this option is not needed.
71
+ Use this option when non-default library paths are needed.
72
+
68
73
  * `--with-sanitize[=address,cfi,integer,memory,thread,undefined]` -
69
74
  Enable sanitizers for Clang / GCC. If no argument is given, try to enable
70
75
  all sanitizers or fail if none are available. If a command-separated list of
@@ -89,13 +94,48 @@ the library file `libmysqlclient.so` but is missing the header file `mysql.h`
89
94
 
90
95
  ### Mac OS X
91
96
 
92
- You may use MacPorts, Homebrew, or a native MySQL installer package. The most
97
+ You may use Homebrew, MacPorts, or a native MySQL installer package. The most
93
98
  common paths will be automatically searched. If you want to select a specific
94
99
  MySQL directory, use the `--with-mysql-dir` or `--with-mysql-config` options above.
95
100
 
96
101
  If you have not done so already, you will need to install the XCode select tools by running
97
102
  `xcode-select --install`.
98
103
 
104
+ Later versions of MacOS no longer distribute a linkable OpenSSL library. It is
105
+ common to use Homebrew or MacPorts to install OpenSSL. Make sure that both the
106
+ Ruby runtime and MySQL client libraries are compiled with the same OpenSSL
107
+ family, 1.0 or 1.1 or 3.0, since only one can be loaded at runtime.
108
+
109
+ ``` sh
110
+ $ brew install openssl@1.1
111
+ $ gem install mysql2 -- --with-openssl-dir=$(brew --prefix openssl@1.1)
112
+
113
+ or
114
+
115
+ $ sudo port install openssl11
116
+ ```
117
+
118
+ Since most Ruby projects use Bundler, you can set build options in the Bundler
119
+ config rather than manually installing a global mysql2 gem. This example shows
120
+ how to set build arguments with [Bundler config](https://bundler.io/man/bundle-config.1.html):
121
+
122
+ ``` sh
123
+ $ bundle config --local build.mysql2 -- --with-openssl-dir=$(brew --prefix openssl@1.1)
124
+ ```
125
+
126
+ Another helpful trick is to use the same OpenSSL library that your Ruby was
127
+ built with, if it was built with an alternate OpenSSL path. This example finds
128
+ the argument `--with-openssl-dir=/some/path` from the Ruby build and adds that
129
+ to the [Bundler config](https://bundler.io/man/bundle-config.1.html):
130
+
131
+ ``` sh
132
+ $ bundle config --local build.mysql2 -- $(ruby -r rbconfig -e 'puts RbConfig::CONFIG["configure_args"]' | xargs -n1 | grep with-openssl-dir)
133
+ ```
134
+
135
+ Note the additional double dashes (`--`) these separate command-line arguments
136
+ that `gem` or `bundler` interpret from the addiitonal arguments that are passed
137
+ to the mysql2 build process.
138
+
99
139
  ### Windows
100
140
 
101
141
  Make sure that you have Ruby and the DevKit compilers installed. We recommend
@@ -205,7 +245,7 @@ result = statement.execute(1, "CA", :as => :array)
205
245
 
206
246
  Session Tracking information can be accessed with
207
247
 
208
- ```ruby
248
+ ``` ruby
209
249
  c = Mysql2::Client.new(
210
250
  host: "127.0.0.1",
211
251
  username: "root",
@@ -241,7 +281,6 @@ Mysql2::Client.new(
241
281
  :reconnect = true/false,
242
282
  :local_infile = true/false,
243
283
  :secure_auth = true/false,
244
- :ssl_mode = :disabled / :preferred / :required / :verify_ca / :verify_identity,
245
284
  :default_file = '/path/to/my.cfg',
246
285
  :default_group = 'my.cfg section',
247
286
  :default_auth = 'authentication_windows_client'
@@ -262,14 +301,13 @@ type of connection to make, with special interpretation you should be aware of:
262
301
  * An IPv4 or IPv6 address will result in a TCP connection.
263
302
  * Any other value will be looked up as a hostname for a TCP connection.
264
303
 
265
- ### SSL options
304
+ ### SSL/TLS options
266
305
 
267
- Setting any of the following options will enable an SSL connection, but only if
268
- your MySQL client library and server have been compiled with SSL support.
269
- MySQL client library defaults will be used for any parameters that are left out
270
- or set to nil. Relative paths are allowed, and may be required by managed
271
- hosting providers such as Heroku. Set `:sslverify => true` to require that the
272
- server presents a valid certificate.
306
+ Setting any of the following options will enable an SSL/TLS connection, but
307
+ only if your MySQL client library and server have been compiled with SSL
308
+ support. MySQL client library defaults will be used for any parameters that are
309
+ left out or set to nil. Relative paths are allowed, and may be required by
310
+ managed hosting providers such as Heroku.
273
311
 
274
312
  ``` ruby
275
313
  Mysql2::Client.new(
@@ -279,10 +317,29 @@ Mysql2::Client.new(
279
317
  :sslca => '/path/to/ca-cert.pem',
280
318
  :sslcapath => '/path/to/cacerts',
281
319
  :sslcipher => 'DHE-RSA-AES256-SHA',
282
- :sslverify => true,
320
+ :sslverify => true, # Removed in MySQL 8.0
321
+ :ssl_mode => :disabled / :preferred / :required / :verify_ca / :verify_identity,
283
322
  )
284
323
  ```
285
324
 
325
+ For MySQL versions 5.7.11 and higher, use `:ssl_mode` to prefer or require an
326
+ SSL connection and certificate validation. For earlier versions of MySQL, use
327
+ the `:sslverify` boolean. For details on each of the `:ssl_mode` options, see
328
+ [https://dev.mysql.com/doc/refman/8.0/en/connection-options.html](https://dev.mysql.com/doc/refman/8.0/en/connection-options.html#option_general_ssl-mode).
329
+
330
+ The `:ssl_mode` option will also set the appropriate MariaDB connection flags:
331
+
332
+ | `:ssl_mode` | MariaDB option value |
333
+ | --- | --- |
334
+ | `:disabled` | MYSQL_OPT_SSL_ENFORCE = 0 |
335
+ | `:required` | MYSQL_OPT_SSL_ENFORCE = 1 |
336
+ | `:verify_identity` | MYSQL_OPT_SSL_VERIFY_SERVER_CERT = 1 |
337
+
338
+ MariaDB does not support the `:preferred` or `:verify_ca` options. For more
339
+ information about SSL/TLS in MariaDB, see
340
+ [https://mariadb.com/kb/en/securing-connections-for-client-and-server/](https://mariadb.com/kb/en/securing-connections-for-client-and-server/)
341
+ and [https://mariadb.com/kb/en/mysql_optionsv/#tls-options](https://mariadb.com/kb/en/mysql_optionsv/#tls-options)
342
+
286
343
  ### Secure auth
287
344
 
288
345
  Starting with MySQL 5.6.5, secure_auth is enabled by default on servers (it was disabled by default prior to this).
@@ -329,7 +386,7 @@ In this example, the compression flag is negated with `-COMPRESS`.
329
386
  Active Record typically reads its configuration from a file named `database.yml` or an environment variable `DATABASE_URL`.
330
387
  Use the value `mysql2` as the protocol name. For example:
331
388
 
332
- ``` shell
389
+ ``` sh
333
390
  DATABASE_URL=mysql2://sql_user:sql_pass@sql_host_name:port/sql_db_name?option1=value1&option2=value2
334
391
  ```
335
392
 
@@ -388,7 +445,7 @@ end
388
445
 
389
446
  Yields:
390
447
 
391
- ```ruby
448
+ ``` ruby
392
449
  {"1"=>1}
393
450
  {"2"=>2}
394
451
  next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
@@ -568,14 +625,16 @@ As for field values themselves, I'm workin on it - but expect that soon.
568
625
 
569
626
  This gem is tested with the following Ruby versions on Linux and Mac OS X:
570
627
 
571
- * Ruby MRI 2.0.0, 2.1.x, 2.2.x, 2.3.x, 2.4.x, 2.5.x, 2.6.x
628
+ * Ruby MRI 2.0 through 2.7 (all versions to date)
629
+ * Ruby MRI 3.0, 3.1, 3.2 (all versions to date)
572
630
  * Rubinius 2.x and 3.x do work but may fail under some workloads
573
631
 
574
632
  This gem is tested with the following MySQL and MariaDB versions:
575
633
 
576
634
  * MySQL 5.5, 5.6, 5.7, 8.0
577
- * MySQL Connector/C 6.0 and 6.1 (primarily on Windows)
578
- * MariaDB 5.5, 10.0, 10.1, 10.2, 10.3
635
+ * MySQL Connector/C 6.0, 6.1, 8.0 (primarily on Windows)
636
+ * MariaDB 5.5, 10.x, with a focus on 10.6 LTS and 10.11 LTS
637
+ * MariaDB Connector/C 2.x, 3.x
579
638
 
580
639
  ### Ruby on Rails / Active Record
581
640
 
data/ext/mysql2/client.c CHANGED
@@ -120,53 +120,80 @@ struct nogvl_select_db_args {
120
120
 
121
121
  static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
122
122
  unsigned long version = mysql_get_client_version();
123
+ const char *version_str = mysql_get_client_info();
123
124
 
124
- if (version < 50703) {
125
- rb_warn( "Your mysql client library does not support setting ssl_mode; full support comes with 5.7.11." );
125
+ /* Warn about versions that are known to be incomplete; these are pretty
126
+ * ancient, we want people to upgrade if they need SSL/TLS to work
127
+ *
128
+ * MySQL 5.x before 5.6.30 -- ssl_mode introduced but not fully working until 5.6.36)
129
+ * MySQL 5.7 before 5.7.3 -- ssl_mode introduced but not fully working until 5.7.11)
130
+ */
131
+ if ((version >= 50000 && version < 50630) || (version >= 50700 && version < 50703)) {
132
+ rb_warn("Your mysql client library version %s does not support setting ssl_mode; full support comes with 5.6.36+, 5.7.11+, 8.0+", version_str);
126
133
  return Qnil;
127
134
  }
135
+
136
+ /* For these versions, map from the options we're exposing to Ruby to the constant available:
137
+ * ssl_mode: :verify_identity to MYSQL_OPT_SSL_VERIFY_SERVER_CERT = 1
138
+ * ssl_mode: :required to MYSQL_OPT_SSL_ENFORCE = 1
139
+ * ssl_mode: :disabled to MYSQL_OPT_SSL_ENFORCE = 0
140
+ */
128
141
  #if defined(HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT) || defined(HAVE_CONST_MYSQL_OPT_SSL_ENFORCE)
129
142
  GET_CLIENT(self);
130
- int val = NUM2INT( setting );
131
- // Either MySQL 5.7.3 - 5.7.10, or Connector/C 6.1.3 - 6.1.x, or MariaDB 10.x and later
132
- if ((version >= 50703 && version < 50711) || (version >= 60103 && version < 60200) || version >= 100000) {
143
+ int val = NUM2INT(setting);
144
+
145
+ /* Expected code path for MariaDB 10.x and MariaDB Connector/C 3.x
146
+ * Workaround code path for MySQL 5.7.3 - 5.7.10 and MySQL Connector/C 6.1.3 - 6.1.x
147
+ */
148
+ if (version >= 100000 // MariaDB (all versions numbered 10.x)
149
+ || (version >= 30000 && version < 40000) // MariaDB Connector/C (all versions numbered 3.x)
150
+ || (version >= 50703 && version < 50711) // Workaround for MySQL 5.7.3 - 5.7.10
151
+ || (version >= 60103 && version < 60200)) { // Workaround for MySQL Connector/C 6.1.3 - 6.1.x
133
152
  #ifdef HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT
134
153
  if (val == SSL_MODE_VERIFY_IDENTITY) {
135
154
  my_bool b = 1;
136
- int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &b );
155
+ int result = mysql_options(wrapper->client, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &b);
137
156
  return INT2NUM(result);
138
157
  }
139
158
  #endif
140
159
  #ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
141
160
  if (val == SSL_MODE_DISABLED || val == SSL_MODE_REQUIRED) {
142
- my_bool b = ( val == SSL_MODE_REQUIRED );
143
- int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b );
161
+ my_bool b = (val == SSL_MODE_REQUIRED);
162
+ int result = mysql_options(wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b);
144
163
  return INT2NUM(result);
145
164
  }
146
165
  #endif
147
- rb_warn( "Your mysql client library does not support ssl_mode %d.", val );
166
+ rb_warn("Your mysql client library version %s does not support ssl_mode %d", version_str, val);
148
167
  return Qnil;
149
168
  } else {
150
- rb_warn( "Your mysql client library does not support ssl_mode as expected." );
169
+ rb_warn("Your mysql client library version %s does not support ssl_mode as expected", version_str);
151
170
  return Qnil;
152
171
  }
153
172
  #endif
173
+
174
+ /* For other versions -- known to be MySQL 5.6.36+, 5.7.11+, 8.0+
175
+ * pass the value of the argument to MYSQL_OPT_SSL_MODE -- note the code
176
+ * mapping from atoms / constants is in the MySQL::Client Ruby class
177
+ */
154
178
  #ifdef FULL_SSL_MODE_SUPPORT
155
179
  GET_CLIENT(self);
156
- int val = NUM2INT( setting );
180
+ int val = NUM2INT(setting);
157
181
 
158
182
  if (val != SSL_MODE_DISABLED && val != SSL_MODE_PREFERRED && val != SSL_MODE_REQUIRED && val != SSL_MODE_VERIFY_CA && val != SSL_MODE_VERIFY_IDENTITY) {
159
183
  rb_raise(cMysql2Error, "ssl_mode= takes DISABLED, PREFERRED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY, you passed: %d", val );
160
184
  }
161
- int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_MODE, &val );
185
+ int result = mysql_options(wrapper->client, MYSQL_OPT_SSL_MODE, &val);
162
186
 
163
187
  return INT2NUM(result);
164
188
  #endif
189
+
190
+ // Warn if we get this far
165
191
  #ifdef NO_SSL_MODE_SUPPORT
166
- rb_warn( "Your mysql client library does not support setting ssl_mode; full support comes with 5.7.11." );
192
+ rb_warn("Your mysql client library does not support setting ssl_mode");
167
193
  return Qnil;
168
194
  #endif
169
195
  }
196
+
170
197
  /*
171
198
  * non-blocking mysql_*() functions that we won't be wrapping since
172
199
  * they do not appear to hit the network nor issue any interruptible
@@ -192,11 +219,47 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
192
219
  static void rb_mysql_client_mark(void * wrapper) {
193
220
  mysql_client_wrapper * w = wrapper;
194
221
  if (w) {
195
- rb_gc_mark(w->encoding);
196
- rb_gc_mark(w->active_thread);
222
+ rb_gc_mark_movable(w->encoding);
223
+ rb_gc_mark_movable(w->active_fiber);
197
224
  }
198
225
  }
199
226
 
227
+ /* this is called during GC */
228
+ static void rb_mysql_client_free(void *ptr) {
229
+ mysql_client_wrapper *wrapper = ptr;
230
+ decr_mysql2_client(wrapper);
231
+ }
232
+
233
+ static size_t rb_mysql_client_memsize(const void * wrapper) {
234
+ const mysql_client_wrapper * w = wrapper;
235
+ return sizeof(*w);
236
+ }
237
+
238
+ static void rb_mysql_client_compact(void * wrapper) {
239
+ mysql_client_wrapper * w = wrapper;
240
+ if (w) {
241
+ rb_mysql2_gc_location(w->encoding);
242
+ rb_mysql2_gc_location(w->active_fiber);
243
+ }
244
+ }
245
+
246
+ const rb_data_type_t rb_mysql_client_type = {
247
+ "rb_mysql_client",
248
+ {
249
+ rb_mysql_client_mark,
250
+ rb_mysql_client_free,
251
+ rb_mysql_client_memsize,
252
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
253
+ rb_mysql_client_compact,
254
+ #endif
255
+ },
256
+ 0,
257
+ 0,
258
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
259
+ RUBY_TYPED_FREE_IMMEDIATELY,
260
+ #endif
261
+ };
262
+
200
263
  static VALUE rb_raise_mysql2_error(mysql_client_wrapper *wrapper) {
201
264
  VALUE rb_error_msg = rb_str_new2(mysql_error(wrapper->client));
202
265
  VALUE rb_sql_state = rb_str_new2(mysql_sqlstate(wrapper->client));
@@ -297,18 +360,12 @@ static void *nogvl_close(void *ptr) {
297
360
  mysql_close(wrapper->client);
298
361
  wrapper->closed = 1;
299
362
  wrapper->reconnect_enabled = 0;
300
- wrapper->active_thread = Qnil;
363
+ wrapper->active_fiber = Qnil;
301
364
  }
302
365
 
303
366
  return NULL;
304
367
  }
305
368
 
306
- /* this is called during GC */
307
- static void rb_mysql_client_free(void *ptr) {
308
- mysql_client_wrapper *wrapper = ptr;
309
- decr_mysql2_client(wrapper);
310
- }
311
-
312
369
  void decr_mysql2_client(mysql_client_wrapper *wrapper)
313
370
  {
314
371
  wrapper->refcount--;
@@ -340,9 +397,13 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
340
397
  static VALUE allocate(VALUE klass) {
341
398
  VALUE obj;
342
399
  mysql_client_wrapper * wrapper;
400
+ #ifdef NEW_TYPEDDATA_WRAPPER
401
+ obj = TypedData_Make_Struct(klass, mysql_client_wrapper, &rb_mysql_client_type, wrapper);
402
+ #else
343
403
  obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
404
+ #endif
344
405
  wrapper->encoding = Qnil;
345
- wrapper->active_thread = Qnil;
406
+ wrapper->active_fiber = Qnil;
346
407
  wrapper->automatic_close = 1;
347
408
  wrapper->server_version = 0;
348
409
  wrapper->reconnect_enabled = 0;
@@ -543,7 +604,7 @@ static VALUE do_send_query(VALUE args) {
543
604
  mysql_client_wrapper *wrapper = query_args->wrapper;
544
605
  if ((VALUE)rb_thread_call_without_gvl(nogvl_send_query, query_args, RUBY_UBF_IO, 0) == Qfalse) {
545
606
  /* an error occurred, we're not active anymore */
546
- wrapper->active_thread = Qnil;
607
+ wrapper->active_fiber = Qnil;
547
608
  rb_raise_mysql2_error(wrapper);
548
609
  }
549
610
  return Qnil;
@@ -573,7 +634,7 @@ static void *nogvl_do_result(void *ptr, char use_result) {
573
634
 
574
635
  /* once our result is stored off, this connection is
575
636
  ready for another command to be issued */
576
- wrapper->active_thread = Qnil;
637
+ wrapper->active_fiber = Qnil;
577
638
 
578
639
  return result;
579
640
  }
@@ -599,13 +660,13 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
599
660
  GET_CLIENT(self);
600
661
 
601
662
  /* if we're not waiting on a result, do nothing */
602
- if (NIL_P(wrapper->active_thread))
663
+ if (NIL_P(wrapper->active_fiber))
603
664
  return Qnil;
604
665
 
605
666
  REQUIRE_CONNECTED(wrapper);
606
667
  if ((VALUE)rb_thread_call_without_gvl(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
607
668
  /* an error occurred, mark this connection inactive */
608
- wrapper->active_thread = Qnil;
669
+ wrapper->active_fiber = Qnil;
609
670
  rb_raise_mysql2_error(wrapper);
610
671
  }
611
672
 
@@ -618,7 +679,7 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
618
679
 
619
680
  if (result == NULL) {
620
681
  if (mysql_errno(wrapper->client) != 0) {
621
- wrapper->active_thread = Qnil;
682
+ wrapper->active_fiber = Qnil;
622
683
  rb_raise_mysql2_error(wrapper);
623
684
  }
624
685
  /* no data and no error, so query was not a SELECT */
@@ -645,7 +706,7 @@ struct async_query_args {
645
706
  static VALUE disconnect_and_raise(VALUE self, VALUE error) {
646
707
  GET_CLIENT(self);
647
708
 
648
- wrapper->active_thread = Qnil;
709
+ wrapper->active_fiber = Qnil;
649
710
 
650
711
  /* Invalidate the MySQL socket to prevent further communication.
651
712
  * The GC will come along later and call mysql_close to free it.
@@ -710,7 +771,7 @@ static VALUE disconnect_and_mark_inactive(VALUE self) {
710
771
  GET_CLIENT(self);
711
772
 
712
773
  /* Check if execution terminated while result was still being read. */
713
- if (!NIL_P(wrapper->active_thread)) {
774
+ if (!NIL_P(wrapper->active_fiber)) {
714
775
  if (CONNECTED(wrapper)) {
715
776
  /* Invalidate the MySQL socket to prevent further communication. */
716
777
  #ifndef _WIN32
@@ -725,24 +786,24 @@ static VALUE disconnect_and_mark_inactive(VALUE self) {
725
786
  }
726
787
  /* Skip mysql client check performed before command execution. */
727
788
  wrapper->client->status = MYSQL_STATUS_READY;
728
- wrapper->active_thread = Qnil;
789
+ wrapper->active_fiber = Qnil;
729
790
  }
730
791
 
731
792
  return Qnil;
732
793
  }
733
794
 
734
- void rb_mysql_client_set_active_thread(VALUE self) {
735
- VALUE thread_current = rb_thread_current();
795
+ static void rb_mysql_client_set_active_fiber(VALUE self) {
796
+ VALUE fiber_current = rb_fiber_current();
736
797
  GET_CLIENT(self);
737
798
 
738
799
  // see if this connection is still waiting on a result from a previous query
739
- if (NIL_P(wrapper->active_thread)) {
800
+ if (NIL_P(wrapper->active_fiber)) {
740
801
  // mark this connection active
741
- wrapper->active_thread = thread_current;
742
- } else if (wrapper->active_thread == thread_current) {
802
+ wrapper->active_fiber = fiber_current;
803
+ } else if (wrapper->active_fiber == fiber_current) {
743
804
  rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
744
805
  } else {
745
- VALUE inspect = rb_inspect(wrapper->active_thread);
806
+ VALUE inspect = rb_inspect(wrapper->active_fiber);
746
807
  const char *thr = StringValueCStr(inspect);
747
808
 
748
809
  rb_raise(cMysql2Error, "This connection is in use by: %s", thr);
@@ -806,7 +867,7 @@ static VALUE rb_mysql_query(VALUE self, VALUE sql, VALUE current) {
806
867
  args.sql_len = RSTRING_LEN(args.sql);
807
868
  args.wrapper = wrapper;
808
869
 
809
- rb_mysql_client_set_active_thread(self);
870
+ rb_mysql_client_set_active_fiber(self);
810
871
 
811
872
  #ifndef _WIN32
812
873
  rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);
@@ -1374,12 +1435,31 @@ static VALUE set_charset_name(VALUE self, VALUE value) {
1374
1435
  static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE capath, VALUE cipher) {
1375
1436
  GET_CLIENT(self);
1376
1437
 
1438
+ #ifdef HAVE_MYSQL_SSL_SET
1377
1439
  mysql_ssl_set(wrapper->client,
1378
1440
  NIL_P(key) ? NULL : StringValueCStr(key),
1379
1441
  NIL_P(cert) ? NULL : StringValueCStr(cert),
1380
1442
  NIL_P(ca) ? NULL : StringValueCStr(ca),
1381
1443
  NIL_P(capath) ? NULL : StringValueCStr(capath),
1382
1444
  NIL_P(cipher) ? NULL : StringValueCStr(cipher));
1445
+ #else
1446
+ /* mysql 8.3 does not provide mysql_ssl_set */
1447
+ if (!NIL_P(key)) {
1448
+ mysql_options(wrapper->client, MYSQL_OPT_SSL_KEY, StringValueCStr(key));
1449
+ }
1450
+ if (!NIL_P(cert)) {
1451
+ mysql_options(wrapper->client, MYSQL_OPT_SSL_CERT, StringValueCStr(cert));
1452
+ }
1453
+ if (!NIL_P(ca)) {
1454
+ mysql_options(wrapper->client, MYSQL_OPT_SSL_CA, StringValueCStr(ca));
1455
+ }
1456
+ if (!NIL_P(capath)) {
1457
+ mysql_options(wrapper->client, MYSQL_OPT_SSL_CAPATH, StringValueCStr(capath));
1458
+ }
1459
+ if (!NIL_P(cipher)) {
1460
+ mysql_options(wrapper->client, MYSQL_OPT_SSL_CIPHER, StringValueCStr(cipher));
1461
+ }
1462
+ #endif
1383
1463
 
1384
1464
  return self;
1385
1465
  }
@@ -1689,7 +1769,7 @@ void init_mysql2_client() {
1689
1769
  rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_TRANSACTION_STATE"), INT2NUM(SESSION_TRACK_TRANSACTION_STATE));
1690
1770
  #endif
1691
1771
 
1692
- #if defined(FULL_SSL_MODE_SUPPORT) // MySQL 5.7.11 and above
1772
+ #if defined(FULL_SSL_MODE_SUPPORT) // MySQL 5.6.36 and MySQL 5.7.11 and above
1693
1773
  rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
1694
1774
  rb_const_set(cMysql2Client, rb_intern("SSL_MODE_PREFERRED"), INT2NUM(SSL_MODE_PREFERRED));
1695
1775
  rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(SSL_MODE_REQUIRED));
data/ext/mysql2/client.h CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  typedef struct {
5
5
  VALUE encoding;
6
- VALUE active_thread; /* rb_thread_current() or Qnil */
6
+ VALUE active_fiber; /* rb_fiber_current() or Qnil */
7
7
  long server_version;
8
8
  int reconnect_enabled;
9
9
  unsigned int connect_timeout;
@@ -15,12 +15,19 @@ typedef struct {
15
15
  MYSQL *client;
16
16
  } mysql_client_wrapper;
17
17
 
18
- void rb_mysql_client_set_active_thread(VALUE self);
19
18
  void rb_mysql_set_server_query_flags(MYSQL *client, VALUE result);
20
19
 
20
+ extern const rb_data_type_t rb_mysql_client_type;
21
+
22
+ #ifdef NEW_TYPEDDATA_WRAPPER
23
+ #define GET_CLIENT(self) \
24
+ mysql_client_wrapper *wrapper; \
25
+ TypedData_Get_Struct(self, mysql_client_wrapper, &rb_mysql_client_type, wrapper);
26
+ #else
21
27
  #define GET_CLIENT(self) \
22
28
  mysql_client_wrapper *wrapper; \
23
29
  Data_Get_Struct(self, mysql_client_wrapper, wrapper);
30
+ #endif
24
31
 
25
32
  void init_mysql2_client(void);
26
33
  void decr_mysql2_client(mysql_client_wrapper *wrapper);
@@ -1,6 +1,8 @@
1
1
  require 'mkmf'
2
2
  require 'English'
3
3
 
4
+ ### Some helper functions
5
+
4
6
  def asplode(lib)
5
7
  if RUBY_PLATFORM =~ /mingw|mswin/
6
8
  abort "-----\n#{lib} is missing. Check your installation of MySQL or Connector/C, and try again.\n-----"
@@ -26,20 +28,45 @@ def add_ssl_defines(header)
26
28
  end
27
29
  end
28
30
 
29
- # Homebrew openssl
30
- if RUBY_PLATFORM =~ /darwin/ && system("command -v brew")
31
- openssl_location = `brew --prefix openssl`.strip
32
- $LDFLAGS << " -L#{openssl_location}/lib" if openssl_location
33
- end
31
+ ### Check for Ruby C extention interfaces
34
32
 
35
33
  # 2.1+
36
34
  have_func('rb_absint_size')
37
35
  have_func('rb_absint_singlebit_p')
38
36
 
37
+ # 2.7+
38
+ have_func('rb_gc_mark_movable')
39
+
39
40
  # Missing in RBX (https://github.com/rubinius/rubinius/issues/3771)
40
41
  have_func('rb_wait_for_single_fd')
41
42
 
42
- have_func("rb_enc_interned_str", "ruby.h")
43
+ # 3.0+
44
+ have_func('rb_enc_interned_str', 'ruby.h')
45
+
46
+ ### Find OpenSSL library
47
+
48
+ # User-specified OpenSSL if explicitly specified
49
+ if with_config('openssl-dir')
50
+ _, lib = dir_config('openssl')
51
+ if lib
52
+ # Ruby versions below 2.0 on Unix and below 2.1 on Windows
53
+ # do not properly search for lib directories, and must be corrected:
54
+ # https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/39717
55
+ unless lib && lib[-3, 3] == 'lib'
56
+ @libdir_basename = 'lib'
57
+ _, lib = dir_config('openssl')
58
+ end
59
+ abort "-----\nCannot find library dir(s) #{lib}\n-----" unless lib && lib.split(File::PATH_SEPARATOR).any? { |dir| File.directory?(dir) }
60
+ warn "-----\nUsing --with-openssl-dir=#{File.dirname lib}\n-----"
61
+ $LDFLAGS << " -L#{lib}"
62
+ end
63
+ # Homebrew OpenSSL on MacOS
64
+ elsif RUBY_PLATFORM =~ /darwin/ && system('command -v brew')
65
+ openssl_location = `brew --prefix openssl`.strip
66
+ $LDFLAGS << " -L#{openssl_location}/lib" if openssl_location
67
+ end
68
+
69
+ ### Find MySQL client library
43
70
 
44
71
  # borrowed from mysqlplus
45
72
  # http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb
@@ -48,6 +75,7 @@ dirs = ENV.fetch('PATH').split(File::PATH_SEPARATOR) + %w[
48
75
  /opt/local
49
76
  /opt/local/mysql
50
77
  /opt/local/lib/mysql5*
78
+ /opt/homebrew/opt/mysql*
51
79
  /usr
52
80
  /usr/mysql
53
81
  /usr/local
@@ -136,10 +164,16 @@ have_const('MYSQL_OPTION_MULTI_STATEMENTS_OFF', mysql_h)
136
164
  # to retain compatibility with the typedef in earlier MySQLs.
137
165
  have_type('my_bool', mysql_h)
138
166
 
167
+ # detect mysql functions
168
+ have_func('mysql_ssl_set', mysql_h)
169
+
170
+ ### Compiler flags to help catch errors
171
+
139
172
  # This is our wishlist. We use whichever flags work on the host.
140
173
  # -Wall and -Wextra are included by default.
141
174
  wishlist = [
142
175
  '-Weverything',
176
+ '-Wno-compound-token-split-by-macro', # Fixed in Ruby 2.7+ at https://bugs.ruby-lang.org/issues/17865
143
177
  '-Wno-bad-function-cast', # rb_thread_call_without_gvl returns void * that we cast to VALUE
144
178
  '-Wno-conditional-uninitialized', # false positive in client.c
145
179
  '-Wno-covered-switch-default', # result.c -- enum_field_types (when fully covered, e.g. mysql 5.5)
@@ -164,6 +198,8 @@ end
164
198
 
165
199
  $CFLAGS << ' ' << usable_flags.join(' ')
166
200
 
201
+ ### Sanitizers to help with debugging -- many are available on both Clang/LLVM and GCC
202
+
167
203
  enabled_sanitizers = disabled_sanitizers = []
168
204
  # Specify a comma-separated list of sanitizers, or try them all by default
169
205
  sanitizers = with_config('sanitize')
@@ -181,7 +217,7 @@ when String
181
217
  end
182
218
  end
183
219
 
184
- unless disabled_sanitizers.empty?
220
+ unless disabled_sanitizers.empty? # rubocop:disable Style/IfUnlessModifier
185
221
  abort "-----\nCould not enable requested sanitizers: #{disabled_sanitizers.join(',')}\n-----"
186
222
  end
187
223
 
@@ -198,6 +234,8 @@ unless enabled_sanitizers.empty?
198
234
  $CFLAGS << ' -g -fno-omit-frame-pointer'
199
235
  end
200
236
 
237
+ ### Find MySQL Client on Windows, set RPATH to find the library at runtime
238
+
201
239
  if RUBY_PLATFORM =~ /mswin|mingw/ && !defined?(RubyInstaller)
202
240
  # Build libmysql.a interface link library
203
241
  require 'rake'
@@ -36,6 +36,19 @@ void Init_mysql2(void);
36
36
  typedef bool my_bool;
37
37
  #endif
38
38
 
39
+ // ruby 2.7+
40
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
41
+ #define rb_mysql2_gc_location(ptr) ptr = rb_gc_location(ptr)
42
+ #else
43
+ #define rb_gc_mark_movable(ptr) rb_gc_mark(ptr)
44
+ #define rb_mysql2_gc_location(ptr)
45
+ #endif
46
+
47
+ // ruby 2.2+
48
+ #ifdef TypedData_Make_Struct
49
+ #define NEW_TYPEDDATA_WRAPPER 1
50
+ #endif
51
+
39
52
  #include <client.h>
40
53
  #include <statement.h>
41
54
  #include <result.h>
@@ -51,7 +51,7 @@ mysql2_mysql_enc_name_to_rb_hash (str, len)
51
51
  74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
52
52
  74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
53
53
  74, 74, 74, 74, 74, 74, 74, 74, 15, 5,
54
- 0, 74, 5, 25, 40, 10, 20, 50, 74, 74,
54
+ 0, 30, 5, 25, 40, 10, 20, 50, 74, 74,
55
55
  74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
56
56
  74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
57
57
  74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
@@ -89,7 +89,7 @@ mysql2_mysql_enc_name_to_rb (str, len)
89
89
  {
90
90
  enum
91
91
  {
92
- TOTAL_KEYWORDS = 41,
92
+ TOTAL_KEYWORDS = 42,
93
93
  MIN_WORD_LENGTH = 3,
94
94
  MAX_WORD_LENGTH = 8,
95
95
  MIN_HASH_VALUE = 3,
@@ -133,7 +133,8 @@ mysql2_mysql_enc_name_to_rb (str, len)
133
133
  {"big5", "Big5"},
134
134
  {"euckr", "EUC-KR"},
135
135
  {"latin2", "ISO-8859-2"},
136
- {""}, {""},
136
+ {"utf8mb3", "UTF-8"},
137
+ {""},
137
138
  {"dec8", NULL},
138
139
  {"cp850", "CP850"},
139
140
  {"latin1", "ISO-8859-1"},
@@ -306,5 +306,20 @@ static const char *mysql2_mysql_enc_to_rb[] = {
306
306
  "UTF-8",
307
307
  "UTF-8",
308
308
  "UTF-8",
309
+ "UTF-8",
310
+ "UTF-8",
311
+ "UTF-8",
312
+ "UTF-8",
313
+ "UTF-8",
314
+ "UTF-8",
315
+ "UTF-8",
316
+ "UTF-8",
317
+ "UTF-8",
318
+ "UTF-8",
319
+ "UTF-8",
320
+ "UTF-8",
321
+ "UTF-8",
322
+ "UTF-8",
323
+ "UTF-8",
309
324
  "UTF-8"
310
325
  };
data/ext/mysql2/result.c CHANGED
@@ -31,9 +31,13 @@ static rb_encoding *binaryEncoding;
31
31
  #define MYSQL_TYPE_JSON 245
32
32
  #endif
33
33
 
34
+ #ifndef NEW_TYPEDDATA_WRAPPER
35
+ #define TypedData_Get_Struct(obj, type, ignore, sval) Data_Get_Struct(obj, type, sval)
36
+ #endif
37
+
34
38
  #define GET_RESULT(self) \
35
39
  mysql2_result_wrapper *wrapper; \
36
- Data_Get_Struct(self, mysql2_result_wrapper, wrapper);
40
+ TypedData_Get_Struct(self, mysql2_result_wrapper, &rb_mysql_result_type, wrapper);
37
41
 
38
42
  typedef struct {
39
43
  int symbolizeKeys;
@@ -61,11 +65,11 @@ static VALUE sym_symbolize_keys, sym_as, sym_array, sym_database_timezone,
61
65
  static void rb_mysql_result_mark(void * wrapper) {
62
66
  mysql2_result_wrapper * w = wrapper;
63
67
  if (w) {
64
- rb_gc_mark(w->fields);
65
- rb_gc_mark(w->rows);
66
- rb_gc_mark(w->encoding);
67
- rb_gc_mark(w->client);
68
- rb_gc_mark(w->statement);
68
+ rb_gc_mark_movable(w->fields);
69
+ rb_gc_mark_movable(w->rows);
70
+ rb_gc_mark_movable(w->encoding);
71
+ rb_gc_mark_movable(w->client);
72
+ rb_gc_mark_movable(w->statement);
69
73
  }
70
74
  }
71
75
 
@@ -127,6 +131,48 @@ static void rb_mysql_result_free(void *ptr) {
127
131
  xfree(wrapper);
128
132
  }
129
133
 
134
+ static size_t rb_mysql_result_memsize(const void * wrapper) {
135
+ const mysql2_result_wrapper * w = wrapper;
136
+ size_t memsize = sizeof(*w);
137
+ if (w->stmt_wrapper) {
138
+ memsize += sizeof(*w->stmt_wrapper);
139
+ }
140
+ if (w->client_wrapper) {
141
+ memsize += sizeof(*w->client_wrapper);
142
+ }
143
+ return memsize;
144
+ }
145
+
146
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
147
+ static void rb_mysql_result_compact(void * wrapper) {
148
+ mysql2_result_wrapper * w = wrapper;
149
+ if (w) {
150
+ rb_mysql2_gc_location(w->fields);
151
+ rb_mysql2_gc_location(w->rows);
152
+ rb_mysql2_gc_location(w->encoding);
153
+ rb_mysql2_gc_location(w->client);
154
+ rb_mysql2_gc_location(w->statement);
155
+ }
156
+ }
157
+ #endif
158
+
159
+ static const rb_data_type_t rb_mysql_result_type = {
160
+ "rb_mysql_result",
161
+ {
162
+ rb_mysql_result_mark,
163
+ rb_mysql_result_free,
164
+ rb_mysql_result_memsize,
165
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
166
+ rb_mysql_result_compact,
167
+ #endif
168
+ },
169
+ 0,
170
+ 0,
171
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
172
+ RUBY_TYPED_FREE_IMMEDIATELY,
173
+ #endif
174
+ };
175
+
130
176
  static VALUE rb_mysql_result_free_(VALUE self) {
131
177
  GET_RESULT(self);
132
178
  rb_mysql_result_free_result(wrapper);
@@ -365,7 +411,7 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
365
411
  int enc_index;
366
412
 
367
413
  enc_name = (field.charsetnr-1 < MYSQL2_CHARSETNR_SIZE) ? mysql2_mysql_enc_to_rb[field.charsetnr-1] : NULL;
368
-
414
+
369
415
  if (enc_name != NULL) {
370
416
  /* use the field encoding we were able to match */
371
417
  enc_index = rb_enc_find_index(enc_name);
@@ -1129,7 +1175,11 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
1129
1175
  VALUE obj;
1130
1176
  mysql2_result_wrapper * wrapper;
1131
1177
 
1178
+ #ifdef NEW_TYPEDDATA_WRAPPER
1179
+ obj = TypedData_Make_Struct(cMysql2Result, mysql2_result_wrapper, &rb_mysql_result_type, wrapper);
1180
+ #else
1132
1181
  obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper);
1182
+ #endif
1133
1183
  wrapper->numberOfFields = 0;
1134
1184
  wrapper->numberOfRows = 0;
1135
1185
  wrapper->lastRowProcessed = 0;
@@ -1176,7 +1226,7 @@ void init_mysql2_result() {
1176
1226
  cMysql2Result = rb_define_class_under(mMysql2, "Result", rb_cObject);
1177
1227
  rb_undef_alloc_func(cMysql2Result);
1178
1228
  rb_global_variable(&cMysql2Result);
1179
-
1229
+
1180
1230
  rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1);
1181
1231
  rb_define_method(cMysql2Result, "fields", rb_mysql_result_fetch_fields, 0);
1182
1232
  rb_define_method(cMysql2Result, "field_types", rb_mysql_result_fetch_field_types, 0);
@@ -6,9 +6,13 @@ static VALUE sym_stream, intern_new_with_args, intern_each, intern_to_s, intern_
6
6
  static VALUE intern_sec_fraction, intern_usec, intern_sec, intern_min, intern_hour, intern_day, intern_month, intern_year,
7
7
  intern_query_options;
8
8
 
9
+ #ifndef NEW_TYPEDDATA_WRAPPER
10
+ #define TypedData_Get_Struct(obj, type, ignore, sval) Data_Get_Struct(obj, type, sval)
11
+ #endif
12
+
9
13
  #define GET_STATEMENT(self) \
10
14
  mysql_stmt_wrapper *stmt_wrapper; \
11
- Data_Get_Struct(self, mysql_stmt_wrapper, stmt_wrapper); \
15
+ TypedData_Get_Struct(self, mysql_stmt_wrapper, &rb_mysql_statement_type, stmt_wrapper); \
12
16
  if (!stmt_wrapper->stmt) { rb_raise(cMysql2Error, "Invalid statement handle"); } \
13
17
  if (stmt_wrapper->closed) { rb_raise(cMysql2Error, "Statement handle already closed"); }
14
18
 
@@ -16,9 +20,45 @@ static void rb_mysql_stmt_mark(void * ptr) {
16
20
  mysql_stmt_wrapper *stmt_wrapper = ptr;
17
21
  if (!stmt_wrapper) return;
18
22
 
19
- rb_gc_mark(stmt_wrapper->client);
23
+ rb_gc_mark_movable(stmt_wrapper->client);
24
+ }
25
+
26
+ static void rb_mysql_stmt_free(void *ptr) {
27
+ mysql_stmt_wrapper *stmt_wrapper = ptr;
28
+ decr_mysql2_stmt(stmt_wrapper);
29
+ }
30
+
31
+ static size_t rb_mysql_stmt_memsize(const void * ptr) {
32
+ const mysql_stmt_wrapper *stmt_wrapper = ptr;
33
+ return sizeof(*stmt_wrapper);
20
34
  }
21
35
 
36
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
37
+ static void rb_mysql_stmt_compact(void * ptr) {
38
+ mysql_stmt_wrapper *stmt_wrapper = ptr;
39
+ if (!stmt_wrapper) return;
40
+
41
+ rb_mysql2_gc_location(stmt_wrapper->client);
42
+ }
43
+ #endif
44
+
45
+ static const rb_data_type_t rb_mysql_statement_type = {
46
+ "rb_mysql_statement",
47
+ {
48
+ rb_mysql_stmt_mark,
49
+ rb_mysql_stmt_free,
50
+ rb_mysql_stmt_memsize,
51
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
52
+ rb_mysql_stmt_compact,
53
+ #endif
54
+ },
55
+ 0,
56
+ 0,
57
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
58
+ RUBY_TYPED_FREE_IMMEDIATELY,
59
+ #endif
60
+ };
61
+
22
62
  static void *nogvl_stmt_close(void *ptr) {
23
63
  mysql_stmt_wrapper *stmt_wrapper = ptr;
24
64
  if (stmt_wrapper->stmt) {
@@ -28,11 +68,6 @@ static void *nogvl_stmt_close(void *ptr) {
28
68
  return NULL;
29
69
  }
30
70
 
31
- static void rb_mysql_stmt_free(void *ptr) {
32
- mysql_stmt_wrapper *stmt_wrapper = ptr;
33
- decr_mysql2_stmt(stmt_wrapper);
34
- }
35
-
36
71
  void decr_mysql2_stmt(mysql_stmt_wrapper *stmt_wrapper) {
37
72
  stmt_wrapper->refcount--;
38
73
 
@@ -96,7 +131,11 @@ VALUE rb_mysql_stmt_new(VALUE rb_client, VALUE sql) {
96
131
 
97
132
  Check_Type(sql, T_STRING);
98
133
 
134
+ #ifdef NEW_TYPEDDATA_WRAPPER
135
+ rb_stmt = TypedData_Make_Struct(cMysql2Statement, mysql_stmt_wrapper, &rb_mysql_statement_type, stmt_wrapper);
136
+ #else
99
137
  rb_stmt = Data_Make_Struct(cMysql2Statement, mysql_stmt_wrapper, rb_mysql_stmt_mark, rb_mysql_stmt_free, stmt_wrapper);
138
+ #endif
100
139
  {
101
140
  stmt_wrapper->client = rb_client;
102
141
  stmt_wrapper->refcount = 1;
@@ -448,7 +487,7 @@ static VALUE rb_mysql_stmt_execute(int argc, VALUE *argv, VALUE self) {
448
487
  if (metadata == NULL) {
449
488
  if (mysql_stmt_errno(stmt) != 0) {
450
489
  // either CR_OUT_OF_MEMORY or CR_UNKNOWN_ERROR. both fatal.
451
- wrapper->active_thread = Qnil;
490
+ wrapper->active_fiber = Qnil;
452
491
  rb_raise_mysql2_stmt_error(stmt_wrapper);
453
492
  }
454
493
  // no data and no error, so query was not a SELECT
@@ -461,7 +500,7 @@ static VALUE rb_mysql_stmt_execute(int argc, VALUE *argv, VALUE self) {
461
500
  mysql_free_result(metadata);
462
501
  rb_raise_mysql2_stmt_error(stmt_wrapper);
463
502
  }
464
- wrapper->active_thread = Qnil;
503
+ wrapper->active_fiber = Qnil;
465
504
  }
466
505
 
467
506
  resultObj = rb_mysql_result_to_obj(stmt_wrapper->client, wrapper->encoding, current, metadata, self);
@@ -502,7 +541,7 @@ static VALUE rb_mysql_stmt_fields(VALUE self) {
502
541
  if (metadata == NULL) {
503
542
  if (mysql_stmt_errno(stmt) != 0) {
504
543
  // either CR_OUT_OF_MEMORY or CR_UNKNOWN_ERROR. both fatal.
505
- wrapper->active_thread = Qnil;
544
+ wrapper->active_fiber = Qnil;
506
545
  rb_raise_mysql2_stmt_error(stmt_wrapper);
507
546
  }
508
547
  // no data and no error, so query was not a SELECT
data/lib/mysql2/client.rb CHANGED
@@ -20,6 +20,7 @@ module Mysql2
20
20
 
21
21
  def initialize(opts = {})
22
22
  raise Mysql2::Error, "Options parameter must be a Hash" unless opts.is_a? Hash
23
+
23
24
  opts = Mysql2::Util.key_hash_as_symbols(opts)
24
25
  @read_timeout = nil
25
26
  @query_options = self.class.default_query_options.dup
@@ -33,6 +34,7 @@ module Mysql2
33
34
  # TODO: stricter validation rather than silent massaging
34
35
  %i[reconnect connect_timeout local_infile read_timeout write_timeout default_file default_group secure_auth init_command automatic_close enable_cleartext_plugin default_auth].each do |key|
35
36
  next unless opts.key?(key)
37
+
36
38
  case key
37
39
  when :reconnect, :local_infile, :secure_auth, :automatic_close, :enable_cleartext_plugin
38
40
  send(:"#{key}=", !!opts[key]) # rubocop:disable Style/DoubleNegation
@@ -136,6 +138,7 @@ module Mysql2
136
138
  # and performance_schema.session_account_connect_attrs
137
139
  def parse_connect_attrs(conn_attrs)
138
140
  return {} if Mysql2::Client::CONNECT_ATTRS.zero?
141
+
139
142
  conn_attrs ||= {}
140
143
  conn_attrs[:program_name] ||= $PROGRAM_NAME
141
144
  conn_attrs.each_with_object({}) do |(key, value), hash|
@@ -152,6 +155,7 @@ module Mysql2
152
155
  def query_info
153
156
  info = query_info_string
154
157
  return {} unless info
158
+
155
159
  info_hash = {}
156
160
  info.split.each_slice(2) { |s| info_hash[s[0].downcase.delete(':').to_sym] = s[1].to_i }
157
161
  info_hash
@@ -1,3 +1,3 @@
1
1
  module Mysql2
2
- VERSION = "0.5.4".freeze
2
+ VERSION = "0.5.6".freeze
3
3
  end
data/lib/mysql2.rb CHANGED
@@ -65,6 +65,7 @@ module Mysql2
65
65
  #
66
66
  def self.key_hash_as_symbols(hash)
67
67
  return nil unless hash
68
+
68
69
  Hash[hash.map { |k, v| [k.to_sym, v] }]
69
70
  end
70
71
 
@@ -0,0 +1,104 @@
1
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
2
+
3
+ xsFNBFb8EKsBEADwGmleOSVThrbCyCVUdCreMTKpmD5p5aPz/0jc66050MAb71Hv
4
+ TVcfuMqHYO8O66qXLpEdqZpuk4D+rw1oKyC+d8uPD2PSHRqBXnR0Qf+LVTZvtO92
5
+ 3R7pYnC2x6V6iVGpKQYFP8cwh2B1qgIa+9y/N8cQIqfD+0ghyiUjjTYek3YFBnqa
6
+ L/2h2V0Mt0DkBrDK80LqEY10PAFDfJjINAW9XNHZzi2KqUx5w1z8rItokXV6fYE5
7
+ ItyGMR6WVajJg5D4VCiZd0ymuQP2bGkrRbl6FH5vofVSkahKMJeHs2lbvMvNyS3c
8
+ n8vxoBvbbcwSAV1gvB1uzXXxv0kdkFZjhU1Tss4+Dak8qeEmIrC5qYycLxIdVEhT
9
+ Z8N8+P7Dll+QGOZKu9+OzhQ+byzpLFhUHKys53eXo/HrfWtw3DdP21yyb5P3QcgF
10
+ scxfZHzZtFNUL6XaVnauZM2lqquUW+lMNdKKGCBJ6co4QxjocsxfISyarcFj6ZR0
11
+ 5Hf6VU3Y7AyuFZdL0SQWPv9BSu/swBOimrSiiVHbtE49Nx1x/d1wn1peYl07WRUv
12
+ C10eF36ZoqEuSGmDz59mWlwB3daIYAsAAiBwgcmN7aSB8XD4ZPUVSEZvwSm/IwuS
13
+ Rkpde+kIhTLjyv5bRGqU2P/Mi56dB4VFmMJaF26CiRXatxhXOAIAF9dXCwARAQAB
14
+ zS1NYXJpYURCIFNpZ25pbmcgS2V5IDxzaWduaW5nLWtleUBtYXJpYWRiLm9yZz7C
15
+ wXgEEwEIACIFAlb8EKsCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEPFl
16
+ byTHTNHYJZ0P/2Z2RURRkSTHLKZ/GqSvPReReeB7AI+ZrDapkpG/26xp1Yw1isCO
17
+ y99pvQ7hjTFhdZQ7xSRUiT/e27wJxR7s4G/ck5VOVjuJzGnByNLmwMjdN1ONIO9P
18
+ hQAs2iF3uoIbVTxzXof2F8C0WSbKgEWbtqlCWlaapDpN8jKAWdsQsNMdXcdpJ2os
19
+ WiacQRxLREBGjVRkAiqdjYkegQ4BZ0GtPULKjZWCUNkaat51b7O7V19nSy/T7MM7
20
+ n+kqYQLMIHCF8LGd3QQsNppRnolWVRzXMdtR2+9iI21qv6gtHcMiAg6QcKA7halL
21
+ kCdIS2nWR8g7nZeZjq5XhckeNGrGX/3w/m/lwczYjMUer+qs2ww5expZJ7qhtSta
22
+ lE3EtL/l7zE4RlknqwDZ0IXtxCNPu2UovCzZmdZm8UWfMSKk/3VgL8HgzYRr8fo0
23
+ yj0XkckJ7snXvuhoviW2tjm46PyHPWRKgW4iEzUrB+hiXpy3ikt4rLRg/iMqKjyf
24
+ mvcE/VdmFVtsfbfRVvlaWiIWCndRTVBkAaTu8DwrGyugQsbjEcK+4E25/SaKIJIw
25
+ qfxpyBVhru21ypgEMAw1Y8KC7KntB7jzpFotE4wpv1jZKUZuy71ofr7g3/2O+7nW
26
+ LrR1mncbuT6yXo316r56dfKzOxQJBnYFwTjXfa65yBArjQBUCPNYOKr0wkYEEhEI
27
+ AAYFAlb8JFYACgkQy8sIKhu5Q9snYACgh3id41CYTHELOQ/ymj4tiuFt1lcAn3JU
28
+ 9wH3pihM9ISvoeuGnwwHhcKnwsFcBBIBCAAGBQJW/CSEAAoJEJFxGJmV5Fqe11cP
29
+ /A3QhvqleuRaXoS5apIY3lrDL79Wo0bkydM3u2Ft9EqVVG5zZvlmWaXbw5wkPhza
30
+ 7YUjrD7ylaE754lHI48jJp3KY7RosClY/Kuk56GJI/SoMKx4v518pAboZ4hjY9MY
31
+ gmiAuZEYx5Ibv1pj0+hkzRI78+f6+d5QTQ6y/35ZjSSJcBgCMAr/JRsmOkHu6cY6
32
+ qOpq4g8mvRAX5ivRm4UxE2gnxZyd2LjY2/S2kCZvHWVaZuiTD0EU1jYPoOo6fhc8
33
+ zjs5FWS56C1vp7aFOGBvsH3lwYAYi1K2S+/B4nqpitYJz/T0zFzzyYe7ZG77DXKD
34
+ /XajD22IzRGKjoeVPFBx+2V0YCCpWZkqkfZ2Dt3QVW//QIpVsOJnmaqolDg1sxoa
35
+ BEYBtCtovU0wh1pXWwfn7IgjIkPNl0AU8mW8Ll91WF+Lss/oMrUJMKVDenTJ6/ZO
36
+ 06c+JFlP7dS3YGMsifwgy5abA4Xy4GWpAsyEM68mqsJUc7ZANZcQAKr6+DryzSfI
37
+ Olsn3kJzOtb/c3JhVmblEO6XzdfZJK/axPOp3mF1oEBoJ56fGwO2usgVwQDyLt3J
38
+ iluJrCvMSBL9KtBZWrTZH5t3rTMN0NUALy4Etd6Y8V94i8c5NixMDyjRU7aKJAAw
39
+ tUvxLd12dqtaXsuvGyzLbR4EDT/Q5DfLC1DZWpgtUtCVwsFcBBIBCAAGBQJW/CS2
40
+ AAoJEEHdwLQNpW8iMUoP/AjFKyZ+inQTI2jJJBBtrLjxaxZSG5ggCovowWn8NWv6
41
+ bQBm2VurYVKhvY1xUyxoLY8KN+MvoeTdpB3u7z+M6x+CdfoTGqWQ2yapOC0eEJBF
42
+ O+GFho2WE0msiO0IaVJrzdFTPE0EYR2BHziLu0DDSZADe1WYEqkkrZsCNgi6EMng
43
+ mX2h+DK2GlC3W2tY9sc63DsgzjcMBO9uYmpHj6nizsIrETqouVNUCLT0t8iETa25
44
+ Mehq/I92I70Qfebv7R4eMrs+tWXKyPU0OjV+8b8saZsv1xn98UkeXwYx4JI04OTw
45
+ nBeJG8yPrGDBO5iucmtaCvwGQ3c76qBivrA8eFz3azRxQYWWiFrkElTg+C/E83JQ
46
+ WgqPvPZkI5UHvBwBqcoIXG15AJoXA/ZWIB8nPKWKaV5KDnY3DBuA4rh5Mhy3xwcC
47
+ /22E/CmZMXjUUvDnlPgXCYAYU0FBbGk7JpSYawtNfdAN2XBRPq5sDKLLxftx7D8u
48
+ ESJXXAlPxoRh7x1ArdGM+EowlJJ0xpINBaT0Z/Hk0jxNIFEak796/WeGqewdOIki
49
+ dAs4tppUfzosla5K+qXfWwmhcKmpwA4oynE8wIaoXptoi8+rxaw4N6wAXlSrVxeC
50
+ VTnb7+UY/BT2Wx6IQ10C9jrsj6XIffMvngIinCD9Czvadmr7BEIxKt1LP+gGA8Zg
51
+ wsFcBBIBCgAGBQJYE6oDAAoJEL7YRJ/O6NqIJ24P+QFNa2O+Q1rLKrQiuPw4Q73o
52
+ 7/blUpFNudZfeCDpDbUgJ01u1RHnWOyLcyknartAosFDJIpgcXY5I8jsBIO5IZPR
53
+ C/UKxZB3RYOhj49bySD9RNapHyq+Y56j9JUoz6tkKFBd+6g85Ej8d924xM1UnRCS
54
+ 9cfI9W0fSunbCi2CXLbXFF7V+m3Ou1SVYGIAxpMn4RXyYfuqeB5wROR2GA5Ef6T3
55
+ S5byh1dRSEgnrBToENtp5n7Jwsc9pDofjtaUkO854l45IqFarGjCHZwtNRKd2lcK
56
+ FMnd1jS0nfGkUbn3qNJam1qaGWx4gXaT845VsYYVTbxtkKi+qPUIoOyYx4NEm6fC
57
+ ZywH72oP+fmUT/fbfSHa5j137dRqokkR6RFjnEMBl6WHwgqqUqeIT6t9uV6WWzX9
58
+ lNroZFAFL/de7H31iIRuZcm38DUZOfjVf9glweu4yFvuJ7cQtyQydFQJV4LGDT/C
59
+ 8e9TWrV1/gWMyMGQlZsRWa+h+FfFUccQtfSdXpvSxtXfop+fVQmJgUUl92jh4K9j
60
+ c9a6rIp5v1Q1yEgs2iS50/V/NMSmEcE1XMOxFt9fX9T+XmKAWZ8L25lpILsHT3mB
61
+ VWrpHdbawUaiBp9elxhn6tFiTFR7qA7dlUyWrI+MMlINwSZ2AAXvmA2IajH/UIlh
62
+ xotxmSNiZYIQ6UbD3fk4wsFzBBABCgAdFiEEmy/52H2krRdju+d2+GQcuhDvLUgF
63
+ Ally44wACgkQ+GQcuhDvLUgkjQ//c3mBxfJm6yLAJD4s4OgsPv4pcp/EKmPcdztm
64
+ W0/glwopUZmq9oNo3VMMCGtusrQgpACzfUlesu9NWlPCB3olZkeGugygo0zuQBKs
65
+ 55eG7bPzMLyfSqLKyogYocaGc4lpf4lbvlvxy37YGVrGpwT9i8t2REtM6iPKDcMM
66
+ sgVtNlqFdq3Fs2Haqt0m1EksX6/GSIrjK4LZEcPklrGPvUS3S+qkwuaGE/jXxncE
67
+ 4jFQR9SYH6AHr6Vkt1CG9Dgpr+Ph0I9n0JRknBYoUZ1q51WdF946NplXkCskdzWG
68
+ RHgMUCz3ZehF1FzpKgfO9Zd0YZsmivV/g6frUw/TayP9gxKPt7z2Lsxzyh8X7cg6
69
+ TAvdG9JbG0PyPJT1TZ8qpjP/PtqPclHsHQQIbGSDFWzRM5znhS+5sgyw8FWInjw8
70
+ JjxoOWMa50464EfGeb2jZfwtRimJAJLWEf/JnvO779nXf5YbvUZgfXaX7k/cvCVk
71
+ U8M7oC7x8o6F0P2Lh6FgonklKEeIRtZBUNZ0Lk9OShVqlU9/v16MHq/Eyu/Mbs0D
72
+ en3vYgiYxOBR8czD1Wh4vsKiGfOzQ6oWti/DCURV+iTYhJc7mSWM6STzUFr0nCnF
73
+ x6W0j/zH6ZgiFAGOyIXW2DwfjFvYRcBL1RWAEKsiFwYrNV+MDonjKXjpVB1Ra90o
74
+ lLrZXAXCwHMEEgEKAB0WIQRMRw//78TT3Fl3hlXOGj3V48lPSQUCXAAgOgAKCRDO
75
+ Gj3V48lPSQxAB/43qoWteVZEiN3JW4FnHg+S60TnHSP69FKV+363XYKDa23pNpv4
76
+ tiJumo9Kvb4UoDft766/URHm5RKyPtrxy+wqotamrkGJUTtP2a68h7C31VX+pf6i
77
+ iQKmxRQz4zmW0pA5X01+AgpvcDH++Fv5NLBpnjqPdTh5b0gvr89E0zMNldNYOZu1
78
+ 0H/mukrnGlFDu/osBuy+XJtP2MeasazVMLvjKs+hr//E+iLI9DZOwFBK6AX5gkkI
79
+ UEHkSeb4//AHwvanUMin9un9+F9iR+qDuDEKxuevYzM0owuoVcK5pAsRnRQJlnHW
80
+ /0BQ6FtNGpmljhvUk8a/l3xFf3z/uJG5vVKVzsFNBFb8EKsBEADDfCMsu2U1CdJh
81
+ r4xp6z4J89/tMnpCQASC8DQhtZ6bWG/ksyKt2DnDQ050XBEng+7epzHWA2UgT0li
82
+ Y05zZmFs1X7QeZr16B7JANq6fnHOdZB0ThS7JEYbProkMxcqAFLAZJCpZT534Gpz
83
+ W7qHwzjV+d13IziCHdi6+DD5eavYzBqY8QzjlOXbmIlY7dJUCwXTECUfirc6kH86
84
+ CS8fXZTke4QYZ55VnrOomB4QGqP371kwBETnhlhi74+pvi3jW05Z5x1tVMwuugyz
85
+ zkseZp1VYmJq5SHNFZ/pnAQLE9gUDTb6UWcPBwQh9Sw+7ahSK74lJKYm3wktyvZh
86
+ zAxbNyzs1M56yeFP6uFwJTBfNByyMAa6TGUhNkxlLcYjxKbVmoAnKCVM8t41TlLv
87
+ /a0ki8iQxqvphVLufksR9IpN6d3F15j6GeyVtxBEv04iv4vbuKthWytb+gjX4bI8
88
+ CAo9jGHevmtdiw/SbeKx2YBM1MF6eua37rFMooOBj4X7VfQCyS+crNsOQn8nJGah
89
+ YbzUDCCgnX+pqN9iZvXisMS79wVyD5DyISFDvT/5jY7IXxPibxr10P/8lfW1d72u
90
+ xyI2UiZKZpyHCt4k47yMq4KQGLGuhxJ6q6O3bi2aXRuz8bLqTBLca9dmx9wZFvRh
91
+ 6jS/SKEg7eFcY0xbb6RVIv1UwGDYfQARAQABwsFfBBgBCAAJBQJW/BCrAhsMAAoJ
92
+ EPFlbyTHTNHYEBIQAJhFTh1u34Q+5bnfiM2dAdCr6T6w4Y1v9ePiIYdSImeseJS2
93
+ yRglpLcMjW0uEA9KXiRtC/Nm/ClnqYJzCKeIaweHqH6dIgJKaXZFt1Uaia7X9tDD
94
+ wqALGu97irUrrV1Kh9IkM0J29Vid5amakrdS4mwt2uEISSnCi7pfVoEro+S7tYQ9
95
+ iH6APVIwqWvcaty3cANdwKWfUQZ6a9IQ08xqzaMhMp2VzhVrWkq3B0j2aRoZR7BN
96
+ LH2I7Z0giIM8ARjZs99aTRL+SfMEQ3sUxNLb3KWP/n1lSFbrk4HGzqUBBfczESlN
97
+ c0970C6znK0H0HD11/3BTkMuPqww+Tzex4dpMQllMEKZ3wEyd9v6ba+nj/P1FHSE
98
+ y/VN6IXzd82s1lYOonKTdmXAIROcHnb0QUzwsd/mhB3jKhEDOV2ZcBTD3yHv8m7C
99
+ 9G9y4hV+7yQlnPlSg3DjBp3SS5r+sOObCIy2Ad32upoXkilWa9g7GZSuhY9kyKqe
100
+ Eba1lgXXaQykEeqx0pexkWavNnb9JaPrAZHDjUGcXrREmjEyXyElRoD4CrWXySe4
101
+ 6jCuNhVVlkLGo7osefynXa/+PNjQjURtx8en7M9A1FkQuRAxE8KIZgZzYxkGl5o5
102
+ POSFCA4JUoRPDcrl/sI3fuq2dIOE/BJ2r8dV+LddiR+iukhXRwJXH8RVVEUS
103
+ =mCOI
104
+ -----END PGP PUBLIC KEY BLOCK-----
@@ -33,6 +33,7 @@ mysql_to_rb = {
33
33
  "macroman" => "macRoman",
34
34
  "cp852" => "CP852",
35
35
  "latin7" => "ISO-8859-13",
36
+ "utf8mb3" => "UTF-8",
36
37
  "utf8mb4" => "UTF-8",
37
38
  "cp1251" => "Windows-1251",
38
39
  "utf16" => "UTF-16",
@@ -55,7 +56,7 @@ encodings_with_nil = Array.new(encodings.size)
55
56
  collations.each do |collation|
56
57
  mysql_col_idx = collation[2].to_i
57
58
  rb_enc = mysql_to_rb.fetch(collation[1]) do |mysql_enc|
58
- $stderr.puts "WARNING: Missing mapping for collation \"#{collation[0]}\" with encoding \"#{mysql_enc}\" and id #{mysql_col_idx}, assuming NULL"
59
+ warn "WARNING: Missing mapping for collation \"#{collation[0]}\" with encoding \"#{mysql_enc}\" and id #{mysql_col_idx}, assuming NULL"
59
60
  "NULL"
60
61
  end
61
62
  encodings[mysql_col_idx - 1] = [mysql_col_idx, rb_enc]
@@ -28,6 +28,7 @@ mysql_to_rb = {
28
28
  "macroman" => "macRoman",
29
29
  "cp852" => "CP852",
30
30
  "latin7" => "ISO-8859-13",
31
+ "utf8mb3" => "UTF-8",
31
32
  "utf8mb4" => "UTF-8",
32
33
  "cp1251" => "Windows-1251",
33
34
  "utf16" => "UTF-16",
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mysql2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.4
4
+ version: 0.5.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Lopez
8
8
  - Aaron Stone
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-05-03 00:00:00.000000000 Z
12
+ date: 2024-02-08 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description:
14
+ description:
15
15
  email:
16
16
  - seniorlopez@gmail.com
17
17
  - aaron@serendipity.cx
@@ -48,6 +48,7 @@ files:
48
48
  - lib/mysql2/version.rb
49
49
  - support/3A79BD29.asc
50
50
  - support/5072E1F5.asc
51
+ - support/C74CD1D8.asc
51
52
  - support/libmysql.def
52
53
  - support/mysql_enc_to_ruby.rb
53
54
  - support/ruby_enc_to_mysql.rb
@@ -56,12 +57,12 @@ licenses:
56
57
  - MIT
57
58
  metadata:
58
59
  bug_tracker_uri: https://github.com/brianmario/mysql2/issues
59
- changelog_uri: https://github.com/brianmario/mysql2/releases/tag/0.5.4
60
- documentation_uri: https://www.rubydoc.info/gems/mysql2/0.5.4
60
+ changelog_uri: https://github.com/brianmario/mysql2/releases/tag/0.5.6
61
+ documentation_uri: https://www.rubydoc.info/gems/mysql2/0.5.6
61
62
  homepage_uri: https://github.com/brianmario/mysql2
62
- source_code_uri: https://github.com/brianmario/mysql2/tree/0.5.4
63
+ source_code_uri: https://github.com/brianmario/mysql2/tree/0.5.6
63
64
  msys2_mingw_dependencies: libmariadbclient
64
- post_install_message:
65
+ post_install_message:
65
66
  rdoc_options:
66
67
  - "--charset=UTF-8"
67
68
  require_paths:
@@ -77,8 +78,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
78
  - !ruby/object:Gem::Version
78
79
  version: '0'
79
80
  requirements: []
80
- rubygems_version: 3.0.3.1
81
- signing_key:
81
+ rubygems_version: 3.6.0.dev
82
+ signing_key:
82
83
  specification_version: 4
83
84
  summary: A simple, fast Mysql library for Ruby, binding to libmysql
84
85
  test_files: []