mysql2 0.4.6-x64-mingw32 → 0.4.7-x64-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c91ffd88dd00fe61ae9bcc968c1b8c8710d499be
4
- data.tar.gz: de64adc5e73a7d0022fee69acafaa36bd6084cd1
3
+ metadata.gz: 453a3e20e7f3dbb02c72c486e02415d905720f93
4
+ data.tar.gz: dd0f4dc57756cbcccc72517b5c87d538eb5f3318
5
5
  SHA512:
6
- metadata.gz: b9dcfc5495fcb0436f1769e30bc5fecfcc4323bc811e52ab63e66126424c4f693d8291b563ad5dfbbdc77f31f0947f54513a48fcb2480e8c5d1e6feef9cb162f
7
- data.tar.gz: c5d91e12c1e24073310ddd54b3fb66f9054ed883573d4715f65b1bba4e437891d8eb76a8a8f3ec9d5e24df12c1e8b87b756acaca448f0a9948e327bacde8287a
6
+ metadata.gz: d9cc3d554e47ab6f68cae1bbc58501a444058f0e2b97f0c3995fbc3a24568417045d0ad53097d600968bcfbf4a7e5c67bf754e3f303cb35ae8041385e3aea8e1
7
+ data.tar.gz: a54f879bc8a39fdc1be5148e7ff0ed02093931ca55e44f30140b921d3f6c6900168f87a39ccff1134232afe9c7f0386a2c77286a5ccc835d02cc6f81dd9ad38f
data/README.md CHANGED
@@ -112,7 +112,7 @@ Connect to a database:
112
112
  ``` ruby
113
113
  # this takes a hash of options, almost all of which map directly
114
114
  # to the familiar database.yml in rails
115
- # See http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/MysqlAdapter.html
115
+ # See http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html
116
116
  client = Mysql2::Client.new(:host => "localhost", :username => "root")
117
117
  ```
118
118
 
@@ -213,6 +213,21 @@ Mysql2::Client.new(
213
213
  )
214
214
  ```
215
215
 
216
+ ### Connecting to localhost
217
+
218
+ The underlying MySQL client library has a special interpretation of the "localhost" default connection host name:
219
+
220
+ 1. Attempt to connect via local socket (as specified in your distribution's my.cnf or `default_file` config file).
221
+ 2. But if the socket is not available, look up "localhost" to find an IP address...
222
+ * The file "/etc/hosts" is generally the source of truth for "localhost", and can override its value.
223
+ * Systems with IPv4 use "127.0.0.1"
224
+ * Systems with IPv6 use "::1"
225
+ * Systems with both IPv4 and IPv6 can be configured to prefer one or the other.
226
+ 3. If an address is found for "localhost", connect to it over TCP/IP.
227
+
228
+ You can be explicit about using either a local socket or a TCP/IP connection,
229
+ and whether to use IPv4 or IPv6, by specifying a value other than "localhost"
230
+ for the `host` or `socket` connection options.
216
231
 
217
232
  ### SSL options
218
233
 
@@ -235,47 +250,6 @@ Mysql2::Client.new(
235
250
  )
236
251
  ```
237
252
 
238
- ### Multiple result sets
239
-
240
- You can also retrieve multiple result sets. For this to work you need to
241
- connect with flags `Mysql2::Client::MULTI_STATEMENTS`. Multiple result sets can
242
- be used with stored procedures that return more than one result set, and for
243
- bundling several SQL statements into a single call to `client.query`.
244
-
245
- ``` ruby
246
- client = Mysql2::Client.new(:host => "localhost", :username => "root", :flags => Mysql2::Client::MULTI_STATEMENTS)
247
- result = client.query('CALL sp_customer_list( 25, 10 )')
248
- # result now contains the first result set
249
- while client.next_result
250
- result = client.store_result
251
- # result now contains the next result set
252
- end
253
- ```
254
-
255
- Repeated calls to `client.next_result` will return true, false, or raise an
256
- exception if the respective query erred. When `client.next_result` returns true,
257
- call `client.store_result` to retrieve a result object. Exceptions are not
258
- raised until `client.next_result` is called to find the status of the respective
259
- query. Subsequent queries are not executed if an earlier query raised an
260
- exception. Subsequent calls to `client.next_result` will return false.
261
-
262
- ``` ruby
263
- result = client.query('SELECT 1; SELECT 2; SELECT A; SELECT 3')
264
- p result.first
265
-
266
- while client.next_result
267
- result = client.store_result
268
- p result.first
269
- end
270
- ```
271
-
272
- Yields:
273
- ```
274
- {"1"=>1}
275
- {"2"=>2}
276
- next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
277
- ```
278
-
279
253
  ### Secure auth
280
254
 
281
255
  Starting wih MySQL 5.6.5, secure_auth is enabled by default on servers (it was disabled by default prior to this).
@@ -332,6 +306,47 @@ It is useful if you want to provide session options which survive reconnection.
332
306
  Mysql2::Client.new(:init_command => "SET @@SESSION.sql_mode = 'STRICT_ALL_TABLES'")
333
307
  ```
334
308
 
309
+ ### Multiple result sets
310
+
311
+ You can also retrieve multiple result sets. For this to work you need to
312
+ connect with flags `Mysql2::Client::MULTI_STATEMENTS`. Multiple result sets can
313
+ be used with stored procedures that return more than one result set, and for
314
+ bundling several SQL statements into a single call to `client.query`.
315
+
316
+ ``` ruby
317
+ client = Mysql2::Client.new(:host => "localhost", :username => "root", :flags => Mysql2::Client::MULTI_STATEMENTS)
318
+ result = client.query('CALL sp_customer_list( 25, 10 )')
319
+ # result now contains the first result set
320
+ while client.next_result
321
+ result = client.store_result
322
+ # result now contains the next result set
323
+ end
324
+ ```
325
+
326
+ Repeated calls to `client.next_result` will return true, false, or raise an
327
+ exception if the respective query erred. When `client.next_result` returns true,
328
+ call `client.store_result` to retrieve a result object. Exceptions are not
329
+ raised until `client.next_result` is called to find the status of the respective
330
+ query. Subsequent queries are not executed if an earlier query raised an
331
+ exception. Subsequent calls to `client.next_result` will return false.
332
+
333
+ ``` ruby
334
+ result = client.query('SELECT 1; SELECT 2; SELECT A; SELECT 3')
335
+ p result.first
336
+
337
+ while client.next_result
338
+ result = client.store_result
339
+ p result.first
340
+ end
341
+ ```
342
+
343
+ Yields:
344
+ ```
345
+ {"1"=>1}
346
+ {"2"=>2}
347
+ next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
348
+ ```
349
+
335
350
  ## Cascading config
336
351
 
337
352
  The default config hash is at:
data/ext/mysql2/client.c CHANGED
@@ -30,15 +30,21 @@ VALUE rb_hash_dup(VALUE other) {
30
30
  rb_raise(cMysql2Error, "MySQL client is not initialized"); \
31
31
  }
32
32
 
33
+ #if defined(HAVE_MYSQL_NET_VIO) || defined(HAVE_ST_NET_VIO)
34
+ #define CONNECTED(wrapper) (wrapper->client->net.vio != NULL && wrapper->client->net.fd != -1)
35
+ #elif defined(HAVE_MYSQL_NET_PVIO) || defined(HAVE_ST_NET_PVIO)
36
+ #define CONNECTED(wrapper) (wrapper->client->net.pvio != NULL && wrapper->client->net.fd != -1)
37
+ #endif
38
+
33
39
  #define REQUIRE_CONNECTED(wrapper) \
34
40
  REQUIRE_INITIALIZED(wrapper) \
35
- if (!wrapper->connected && !wrapper->reconnect_enabled) { \
41
+ if (!CONNECTED(wrapper) && !wrapper->reconnect_enabled) { \
36
42
  rb_raise(cMysql2Error, "MySQL client is not connected"); \
37
43
  }
38
44
 
39
45
  #define REQUIRE_NOT_CONNECTED(wrapper) \
40
46
  REQUIRE_INITIALIZED(wrapper) \
41
- if (wrapper->connected) { \
47
+ if (CONNECTED(wrapper)) { \
42
48
  rb_raise(cMysql2Error, "MySQL connection is already open"); \
43
49
  }
44
50
 
@@ -107,14 +113,13 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
107
113
  return Qnil;
108
114
  }
109
115
  #ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
110
- GET_CLIENT(self);
116
+ GET_CLIENT(self);
111
117
  int val = NUM2INT( setting );
112
118
  if (version >= 50703 && version < 50711) {
113
119
  if (val == SSL_MODE_DISABLED || val == SSL_MODE_REQUIRED) {
114
120
  bool b = ( val == SSL_MODE_REQUIRED );
115
121
  int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b );
116
122
  return INT2NUM(result);
117
-
118
123
  } else {
119
124
  rb_warn( "MySQL client libraries between 5.7.3 and 5.7.10 only support SSL_MODE_DISABLED and SSL_MODE_REQUIRED" );
120
125
  return Qnil;
@@ -122,7 +127,7 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
122
127
  }
123
128
  #endif
124
129
  #ifdef FULL_SSL_MODE_SUPPORT
125
- GET_CLIENT(self);
130
+ GET_CLIENT(self);
126
131
  int val = NUM2INT( setting );
127
132
 
128
133
  if (val != SSL_MODE_DISABLED && val != SSL_MODE_PREFERRED && val != SSL_MODE_REQUIRED && val != SSL_MODE_VERIFY_CA && val != SSL_MODE_VERIFY_IDENTITY) {
@@ -264,11 +269,10 @@ static VALUE invalidate_fd(int clientfd)
264
269
  static void *nogvl_close(void *ptr) {
265
270
  mysql_client_wrapper *wrapper = ptr;
266
271
 
267
- if (wrapper->client) {
272
+ if (!wrapper->closed) {
268
273
  mysql_close(wrapper->client);
269
- xfree(wrapper->client);
270
- wrapper->client = NULL;
271
- wrapper->connected = 0;
274
+ wrapper->closed = 1;
275
+ wrapper->reconnect_enabled = 0;
272
276
  wrapper->active_thread = Qnil;
273
277
  }
274
278
 
@@ -287,7 +291,7 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
287
291
 
288
292
  if (wrapper->refcount == 0) {
289
293
  #ifndef _WIN32
290
- if (wrapper->connected && !wrapper->automatic_close) {
294
+ if (CONNECTED(wrapper) && !wrapper->automatic_close) {
291
295
  /* The client is being garbage collected while connected. Prevent
292
296
  * mysql_close() from sending a mysql-QUIT or from calling shutdown() on
293
297
  * the socket by invalidating it. invalidate_fd() will drop this
@@ -299,10 +303,12 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
299
303
  fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely\n");
300
304
  close(wrapper->client->net.fd);
301
305
  }
306
+ wrapper->client->net.fd = -1;
302
307
  }
303
308
  #endif
304
309
 
305
310
  nogvl_close(wrapper);
311
+ xfree(wrapper->client);
306
312
  xfree(wrapper);
307
313
  }
308
314
  }
@@ -317,9 +323,9 @@ static VALUE allocate(VALUE klass) {
317
323
  wrapper->server_version = 0;
318
324
  wrapper->reconnect_enabled = 0;
319
325
  wrapper->connect_timeout = 0;
320
- wrapper->connected = 0; /* means that a database connection is open */
321
326
  wrapper->initialized = 0; /* means that that the wrapper is initialized */
322
327
  wrapper->refcount = 1;
328
+ wrapper->closed = 0;
323
329
  wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
324
330
 
325
331
  return obj;
@@ -450,7 +456,6 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
450
456
  }
451
457
 
452
458
  wrapper->server_version = mysql_get_server_version(wrapper->client);
453
- wrapper->connected = 1;
454
459
  return self;
455
460
  }
456
461
 
@@ -465,13 +470,23 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
465
470
  static VALUE rb_mysql_client_close(VALUE self) {
466
471
  GET_CLIENT(self);
467
472
 
468
- if (wrapper->connected) {
473
+ if (wrapper->client) {
469
474
  rb_thread_call_without_gvl(nogvl_close, wrapper, RUBY_UBF_IO, 0);
470
475
  }
471
476
 
472
477
  return Qnil;
473
478
  }
474
479
 
480
+ /* call-seq:
481
+ * client.closed?
482
+ *
483
+ * @return [Boolean]
484
+ */
485
+ static VALUE rb_mysql_client_closed(VALUE self) {
486
+ GET_CLIENT(self);
487
+ return CONNECTED(wrapper) ? Qfalse : Qtrue;
488
+ }
489
+
475
490
  /*
476
491
  * mysql_send_query is unlikely to block since most queries are small
477
492
  * enough to fit in a socket buffer, but sometimes large UPDATE and
@@ -591,16 +606,16 @@ static VALUE disconnect_and_raise(VALUE self, VALUE error) {
591
606
  GET_CLIENT(self);
592
607
 
593
608
  wrapper->active_thread = Qnil;
594
- wrapper->connected = 0;
595
609
 
596
610
  /* Invalidate the MySQL socket to prevent further communication.
597
611
  * The GC will come along later and call mysql_close to free it.
598
612
  */
599
- if (wrapper->client) {
613
+ if (CONNECTED(wrapper)) {
600
614
  if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
601
615
  fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, closing unsafely\n");
602
616
  close(wrapper->client->net.fd);
603
617
  }
618
+ wrapper->client->net.fd = -1;
604
619
  }
605
620
 
606
621
  rb_exc_raise(error);
@@ -656,19 +671,21 @@ static VALUE disconnect_and_mark_inactive(VALUE self) {
656
671
 
657
672
  /* Check if execution terminated while result was still being read. */
658
673
  if (!NIL_P(wrapper->active_thread)) {
659
- /* Invalidate the MySQL socket to prevent further communication. */
674
+ if (CONNECTED(wrapper)) {
675
+ /* Invalidate the MySQL socket to prevent further communication. */
660
676
  #ifndef _WIN32
661
- if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
662
- rb_warn("mysql2 failed to invalidate FD safely, closing unsafely\n");
663
- close(wrapper->client->net.fd);
664
- }
677
+ if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
678
+ rb_warn("mysql2 failed to invalidate FD safely, closing unsafely\n");
679
+ close(wrapper->client->net.fd);
680
+ }
665
681
  #else
666
- close(wrapper->client->net.fd);
682
+ close(wrapper->client->net.fd);
667
683
  #endif
684
+ wrapper->client->net.fd = -1;
685
+ }
668
686
  /* Skip mysql client check performed before command execution. */
669
687
  wrapper->client->status = MYSQL_STATUS_READY;
670
688
  wrapper->active_thread = Qnil;
671
- wrapper->connected = 0;
672
689
  }
673
690
 
674
691
  return Qnil;
@@ -886,6 +903,11 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
886
903
  retval = charval;
887
904
  break;
888
905
 
906
+ case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
907
+ boolval = (value == Qfalse ? 0 : 1);
908
+ retval = &boolval;
909
+ break;
910
+
889
911
  default:
890
912
  return Qfalse;
891
913
  }
@@ -1075,7 +1097,7 @@ static void *nogvl_ping(void *ptr) {
1075
1097
  static VALUE rb_mysql_client_ping(VALUE self) {
1076
1098
  GET_CLIENT(self);
1077
1099
 
1078
- if (!wrapper->connected) {
1100
+ if (!CONNECTED(wrapper)) {
1079
1101
  return Qfalse;
1080
1102
  } else {
1081
1103
  return (VALUE)rb_thread_call_without_gvl(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
@@ -1303,6 +1325,10 @@ static VALUE set_init_command(VALUE self, VALUE value) {
1303
1325
  return _mysql_client_options(self, MYSQL_INIT_COMMAND, value);
1304
1326
  }
1305
1327
 
1328
+ static VALUE set_enable_cleartext_plugin(VALUE self, VALUE value) {
1329
+ return _mysql_client_options(self, MYSQL_ENABLE_CLEARTEXT_PLUGIN, value);
1330
+ }
1331
+
1306
1332
  static VALUE initialize_ext(VALUE self) {
1307
1333
  GET_CLIENT(self);
1308
1334
 
@@ -1363,6 +1389,7 @@ void init_mysql2_client() {
1363
1389
  rb_define_singleton_method(cMysql2Client, "info", rb_mysql_client_info, 0);
1364
1390
 
1365
1391
  rb_define_method(cMysql2Client, "close", rb_mysql_client_close, 0);
1392
+ rb_define_method(cMysql2Client, "closed?", rb_mysql_client_closed, 0);
1366
1393
  rb_define_method(cMysql2Client, "abandon_results!", rb_mysql_client_abandon_results, 0);
1367
1394
  rb_define_method(cMysql2Client, "escape", rb_mysql_client_real_escape, 1);
1368
1395
  rb_define_method(cMysql2Client, "server_info", rb_mysql_client_server_info, 0);
@@ -1398,6 +1425,7 @@ void init_mysql2_client() {
1398
1425
  rb_define_private_method(cMysql2Client, "init_command=", set_init_command, 1);
1399
1426
  rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
1400
1427
  rb_define_private_method(cMysql2Client, "ssl_mode=", rb_set_ssl_mode_option, 1);
1428
+ rb_define_private_method(cMysql2Client, "enable_cleartext_plugin=", set_enable_cleartext_plugin, 1);
1401
1429
  rb_define_private_method(cMysql2Client, "initialize_ext", initialize_ext, 0);
1402
1430
  rb_define_private_method(cMysql2Client, "connect", rb_connect, 7);
1403
1431
  rb_define_private_method(cMysql2Client, "_query", rb_query, 2);
@@ -1419,6 +1447,10 @@ void init_mysql2_client() {
1419
1447
  #ifdef CLIENT_LONG_PASSWORD
1420
1448
  rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
1421
1449
  LONG2NUM(CLIENT_LONG_PASSWORD));
1450
+ #else
1451
+ /* HACK because MariaDB 10.2 no longer defines this constant,
1452
+ * but we're using it in our default connection flags. */
1453
+ rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"), INT2NUM(0));
1422
1454
  #endif
1423
1455
 
1424
1456
  #ifdef CLIENT_FOUND_ROWS
data/ext/mysql2/client.h CHANGED
@@ -44,10 +44,9 @@ typedef struct {
44
44
  unsigned int connect_timeout;
45
45
  int active;
46
46
  int automatic_close;
47
- int connected;
48
47
  int initialized;
49
48
  int refcount;
50
- int freed;
49
+ int closed;
51
50
  MYSQL *client;
52
51
  } mysql_client_wrapper;
53
52
 
@@ -105,13 +105,16 @@ else
105
105
  asplode 'mysql.h'
106
106
  end
107
107
 
108
- add_ssl_defines([prefix, 'mysql.h'].compact.join('/'))
109
-
110
108
  %w(errmsg.h mysqld_error.h).each do |h|
111
109
  header = [prefix, h].compact.join '/'
112
110
  asplode h unless have_header header
113
111
  end
114
112
 
113
+ mysql_h = [prefix, 'mysql.h'].compact.join('/')
114
+ add_ssl_defines(mysql_h)
115
+ have_struct_member('MYSQL', 'net.vio', mysql_h)
116
+ have_struct_member('MYSQL', 'net.pvio', mysql_h)
117
+
115
118
  # This is our wishlist. We use whichever flags work on the host.
116
119
  # -Wall and -Wextra are included by default.
117
120
  wishlist = [
@@ -14,11 +14,13 @@ void Init_mysql2(void);
14
14
  #include <mysql_com.h>
15
15
  #include <errmsg.h>
16
16
  #include <mysqld_error.h>
17
+ #include <mysql_version.h>
17
18
  #else
18
19
  #include <mysql/mysql.h>
19
20
  #include <mysql/mysql_com.h>
20
21
  #include <mysql/errmsg.h>
21
22
  #include <mysql/mysqld_error.h>
23
+ #include <mysql/mysql_version.h>
22
24
  #endif
23
25
 
24
26
  #ifdef HAVE_RUBY_ENCODING_H
@@ -468,6 +468,7 @@ static VALUE fields(VALUE self) {
468
468
  rb_encoding *default_internal_enc, *conn_enc;
469
469
  #endif
470
470
  GET_STATEMENT(self);
471
+ GET_CLIENT(stmt_wrapper->client);
471
472
  stmt = stmt_wrapper->stmt;
472
473
 
473
474
  #ifdef HAVE_RUBY_ENCODING_H
@@ -478,12 +479,22 @@ static VALUE fields(VALUE self) {
478
479
  }
479
480
  #endif
480
481
 
481
- metadata = mysql_stmt_result_metadata(stmt);
482
+ metadata = mysql_stmt_result_metadata(stmt);
483
+ if (metadata == NULL) {
484
+ if (mysql_stmt_errno(stmt) != 0) {
485
+ // either CR_OUT_OF_MEMORY or CR_UNKNOWN_ERROR. both fatal.
486
+ wrapper->active_thread = Qnil;
487
+ rb_raise_mysql2_stmt_error(stmt_wrapper);
488
+ }
489
+ // no data and no error, so query was not a SELECT
490
+ return Qnil;
491
+ }
492
+
482
493
  fields = mysql_fetch_fields(metadata);
483
494
  field_count = mysql_stmt_field_count(stmt);
484
495
  field_list = rb_ary_new2((long)field_count);
485
496
 
486
- for(i = 0; i < field_count; i++) {
497
+ for (i = 0; i < field_count; i++) {
487
498
  VALUE rb_field;
488
499
 
489
500
  rb_field = rb_str_new(fields[i].name, fields[i].name_length);