mysql2 0.4.6 → 0.4.10

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: 0f6e6398c4050512cbe22c6994153fb0ab4b3d89
4
- data.tar.gz: 8e6345e8df7b550c7248f86cb374422866ffdd38
3
+ metadata.gz: 75b3d925930b92cf7b1a36fa196d334e245919ac
4
+ data.tar.gz: 2bbe0a78b156f8c5b59643c4d57a7ce19b764bcc
5
5
  SHA512:
6
- metadata.gz: 5b820a05878ea935e6a25b4b1e34bfebaf47fc48a8ef24ff8f8920cc4ecaabfc2f0ba7cd590c8d4c51632d5e564fba11ae35880e0bf3230425a7264341e2625a
7
- data.tar.gz: 32f8d9a642c643225386883f97305be79868984a55a541358983ab70ec07f421dc999e8a656f51044c089a2aecb697d2b217453cf2ce0ca9fe4a17f313131e8e
6
+ metadata.gz: 602f336b5ed83421862b9dec36a9ddbd477dcbacc3ef16d58d5252072dba0bc7f7a955000482414eda1d104bda72ded87f3f4c795f8b4b4d36999bc6ee171e4b
7
+ data.tar.gz: 20281fda66cf4595edc05ac6a933d5f641c2f9f87771e8ace1e9de00902ecea54ddbc2d1b743c3dbd97b48c795d0ad32f9ab785e5848a4f3de92c7ddebeef659
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,18 @@ Mysql2::Client.new(
213
213
  )
214
214
  ```
215
215
 
216
+ ### Connecting to MySQL on localhost and elsewhere
217
+
218
+ The underlying MySQL client library uses the `:host` parameter to determine the
219
+ type of connection to make, with special interpretation you should be aware of:
220
+
221
+ * An empty value or `"localhost"` will attempt a local connection:
222
+ * On Unix, connect to the default local socket path. (To set a custom socket
223
+ path, use the `:socket` parameter).
224
+ * On Windows, connect using a shared-memory connection, if enabled, or TCP.
225
+ * A value of `"."` on Windows specifies a named-pipe connection.
226
+ * An IPv4 or IPv6 address will result in a TCP connection.
227
+ * Any other value will be looked up as a hostname for a TCP connection.
216
228
 
217
229
  ### SSL options
218
230
 
@@ -235,47 +247,6 @@ Mysql2::Client.new(
235
247
  )
236
248
  ```
237
249
 
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
250
  ### Secure auth
280
251
 
281
252
  Starting wih MySQL 5.6.5, secure_auth is enabled by default on servers (it was disabled by default prior to this).
@@ -332,6 +303,47 @@ It is useful if you want to provide session options which survive reconnection.
332
303
  Mysql2::Client.new(:init_command => "SET @@SESSION.sql_mode = 'STRICT_ALL_TABLES'")
333
304
  ```
334
305
 
306
+ ### Multiple result sets
307
+
308
+ You can also retrieve multiple result sets. For this to work you need to
309
+ connect with flags `Mysql2::Client::MULTI_STATEMENTS`. Multiple result sets can
310
+ be used with stored procedures that return more than one result set, and for
311
+ bundling several SQL statements into a single call to `client.query`.
312
+
313
+ ``` ruby
314
+ client = Mysql2::Client.new(:host => "localhost", :username => "root", :flags => Mysql2::Client::MULTI_STATEMENTS)
315
+ result = client.query('CALL sp_customer_list( 25, 10 )')
316
+ # result now contains the first result set
317
+ while client.next_result
318
+ result = client.store_result
319
+ # result now contains the next result set
320
+ end
321
+ ```
322
+
323
+ Repeated calls to `client.next_result` will return true, false, or raise an
324
+ exception if the respective query erred. When `client.next_result` returns true,
325
+ call `client.store_result` to retrieve a result object. Exceptions are not
326
+ raised until `client.next_result` is called to find the status of the respective
327
+ query. Subsequent queries are not executed if an earlier query raised an
328
+ exception. Subsequent calls to `client.next_result` will return false.
329
+
330
+ ``` ruby
331
+ result = client.query('SELECT 1; SELECT 2; SELECT A; SELECT 3')
332
+ p result.first
333
+
334
+ while client.next_result
335
+ result = client.store_result
336
+ p result.first
337
+ end
338
+ ```
339
+
340
+ Yields:
341
+ ```
342
+ {"1"=>1}
343
+ {"2"=>2}
344
+ next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
345
+ ```
346
+
335
347
  ## Cascading config
336
348
 
337
349
  The default config hash is at:
@@ -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
 
@@ -47,7 +53,9 @@ VALUE rb_hash_dup(VALUE other) {
47
53
  * variable to use, but MYSQL_SERVER_VERSION gives the correct numbers when
48
54
  * linking against the server itself
49
55
  */
50
- #ifdef LIBMYSQL_VERSION
56
+ #if defined(MARIADB_CLIENT_VERSION_STR)
57
+ #define MYSQL_LINK_VERSION MARIADB_CLIENT_VERSION_STR
58
+ #elif defined(LIBMYSQL_VERSION)
51
59
  #define MYSQL_LINK_VERSION LIBMYSQL_VERSION
52
60
  #else
53
61
  #define MYSQL_LINK_VERSION MYSQL_SERVER_VERSION
@@ -107,14 +115,13 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
107
115
  return Qnil;
108
116
  }
109
117
  #ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
110
- GET_CLIENT(self);
118
+ GET_CLIENT(self);
111
119
  int val = NUM2INT( setting );
112
120
  if (version >= 50703 && version < 50711) {
113
121
  if (val == SSL_MODE_DISABLED || val == SSL_MODE_REQUIRED) {
114
122
  bool b = ( val == SSL_MODE_REQUIRED );
115
123
  int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b );
116
124
  return INT2NUM(result);
117
-
118
125
  } else {
119
126
  rb_warn( "MySQL client libraries between 5.7.3 and 5.7.10 only support SSL_MODE_DISABLED and SSL_MODE_REQUIRED" );
120
127
  return Qnil;
@@ -122,7 +129,7 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
122
129
  }
123
130
  #endif
124
131
  #ifdef FULL_SSL_MODE_SUPPORT
125
- GET_CLIENT(self);
132
+ GET_CLIENT(self);
126
133
  int val = NUM2INT( setting );
127
134
 
128
135
  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 +271,10 @@ static VALUE invalidate_fd(int clientfd)
264
271
  static void *nogvl_close(void *ptr) {
265
272
  mysql_client_wrapper *wrapper = ptr;
266
273
 
267
- if (wrapper->client) {
274
+ if (!wrapper->closed) {
268
275
  mysql_close(wrapper->client);
269
- xfree(wrapper->client);
270
- wrapper->client = NULL;
271
- wrapper->connected = 0;
276
+ wrapper->closed = 1;
277
+ wrapper->reconnect_enabled = 0;
272
278
  wrapper->active_thread = Qnil;
273
279
  }
274
280
 
@@ -287,7 +293,7 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
287
293
 
288
294
  if (wrapper->refcount == 0) {
289
295
  #ifndef _WIN32
290
- if (wrapper->connected && !wrapper->automatic_close) {
296
+ if (CONNECTED(wrapper) && !wrapper->automatic_close) {
291
297
  /* The client is being garbage collected while connected. Prevent
292
298
  * mysql_close() from sending a mysql-QUIT or from calling shutdown() on
293
299
  * the socket by invalidating it. invalidate_fd() will drop this
@@ -299,10 +305,12 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
299
305
  fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely\n");
300
306
  close(wrapper->client->net.fd);
301
307
  }
308
+ wrapper->client->net.fd = -1;
302
309
  }
303
310
  #endif
304
311
 
305
312
  nogvl_close(wrapper);
313
+ xfree(wrapper->client);
306
314
  xfree(wrapper);
307
315
  }
308
316
  }
@@ -317,9 +325,9 @@ static VALUE allocate(VALUE klass) {
317
325
  wrapper->server_version = 0;
318
326
  wrapper->reconnect_enabled = 0;
319
327
  wrapper->connect_timeout = 0;
320
- wrapper->connected = 0; /* means that a database connection is open */
321
328
  wrapper->initialized = 0; /* means that that the wrapper is initialized */
322
329
  wrapper->refcount = 1;
330
+ wrapper->closed = 0;
323
331
  wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
324
332
 
325
333
  return obj;
@@ -450,7 +458,6 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
450
458
  }
451
459
 
452
460
  wrapper->server_version = mysql_get_server_version(wrapper->client);
453
- wrapper->connected = 1;
454
461
  return self;
455
462
  }
456
463
 
@@ -465,13 +472,23 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
465
472
  static VALUE rb_mysql_client_close(VALUE self) {
466
473
  GET_CLIENT(self);
467
474
 
468
- if (wrapper->connected) {
475
+ if (wrapper->client) {
469
476
  rb_thread_call_without_gvl(nogvl_close, wrapper, RUBY_UBF_IO, 0);
470
477
  }
471
478
 
472
479
  return Qnil;
473
480
  }
474
481
 
482
+ /* call-seq:
483
+ * client.closed?
484
+ *
485
+ * @return [Boolean]
486
+ */
487
+ static VALUE rb_mysql_client_closed(VALUE self) {
488
+ GET_CLIENT(self);
489
+ return CONNECTED(wrapper) ? Qfalse : Qtrue;
490
+ }
491
+
475
492
  /*
476
493
  * mysql_send_query is unlikely to block since most queries are small
477
494
  * enough to fit in a socket buffer, but sometimes large UPDATE and
@@ -591,16 +608,16 @@ static VALUE disconnect_and_raise(VALUE self, VALUE error) {
591
608
  GET_CLIENT(self);
592
609
 
593
610
  wrapper->active_thread = Qnil;
594
- wrapper->connected = 0;
595
611
 
596
612
  /* Invalidate the MySQL socket to prevent further communication.
597
613
  * The GC will come along later and call mysql_close to free it.
598
614
  */
599
- if (wrapper->client) {
615
+ if (CONNECTED(wrapper)) {
600
616
  if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
601
617
  fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, closing unsafely\n");
602
618
  close(wrapper->client->net.fd);
603
619
  }
620
+ wrapper->client->net.fd = -1;
604
621
  }
605
622
 
606
623
  rb_exc_raise(error);
@@ -656,19 +673,21 @@ static VALUE disconnect_and_mark_inactive(VALUE self) {
656
673
 
657
674
  /* Check if execution terminated while result was still being read. */
658
675
  if (!NIL_P(wrapper->active_thread)) {
659
- /* Invalidate the MySQL socket to prevent further communication. */
676
+ if (CONNECTED(wrapper)) {
677
+ /* Invalidate the MySQL socket to prevent further communication. */
660
678
  #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
- }
679
+ if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
680
+ rb_warn("mysql2 failed to invalidate FD safely, closing unsafely\n");
681
+ close(wrapper->client->net.fd);
682
+ }
665
683
  #else
666
- close(wrapper->client->net.fd);
684
+ close(wrapper->client->net.fd);
667
685
  #endif
686
+ wrapper->client->net.fd = -1;
687
+ }
668
688
  /* Skip mysql client check performed before command execution. */
669
689
  wrapper->client->status = MYSQL_STATUS_READY;
670
690
  wrapper->active_thread = Qnil;
671
- wrapper->connected = 0;
672
691
  }
673
692
 
674
693
  return Qnil;
@@ -866,10 +885,12 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
866
885
  retval = &boolval;
867
886
  break;
868
887
 
888
+ #ifdef MYSQL_SECURE_AUTH
869
889
  case MYSQL_SECURE_AUTH:
870
890
  boolval = (value == Qfalse ? 0 : 1);
871
891
  retval = &boolval;
872
892
  break;
893
+ #endif
873
894
 
874
895
  case MYSQL_READ_DEFAULT_FILE:
875
896
  charval = (const char *)StringValueCStr(value);
@@ -886,6 +907,13 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
886
907
  retval = charval;
887
908
  break;
888
909
 
910
+ #ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
911
+ case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
912
+ boolval = (value == Qfalse ? 0 : 1);
913
+ retval = &boolval;
914
+ break;
915
+ #endif
916
+
889
917
  default:
890
918
  return Qfalse;
891
919
  }
@@ -1075,7 +1103,7 @@ static void *nogvl_ping(void *ptr) {
1075
1103
  static VALUE rb_mysql_client_ping(VALUE self) {
1076
1104
  GET_CLIENT(self);
1077
1105
 
1078
- if (!wrapper->connected) {
1106
+ if (!CONNECTED(wrapper)) {
1079
1107
  return Qfalse;
1080
1108
  } else {
1081
1109
  return (VALUE)rb_thread_call_without_gvl(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
@@ -1288,7 +1316,12 @@ static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE
1288
1316
  }
1289
1317
 
1290
1318
  static VALUE set_secure_auth(VALUE self, VALUE value) {
1319
+ /* This option was deprecated in MySQL 5.x and removed in MySQL 8.0 */
1320
+ #ifdef MYSQL_SECURE_AUTH
1291
1321
  return _mysql_client_options(self, MYSQL_SECURE_AUTH, value);
1322
+ #else
1323
+ return Qfalse;
1324
+ #endif
1292
1325
  }
1293
1326
 
1294
1327
  static VALUE set_read_default_file(VALUE self, VALUE value) {
@@ -1303,6 +1336,14 @@ static VALUE set_init_command(VALUE self, VALUE value) {
1303
1336
  return _mysql_client_options(self, MYSQL_INIT_COMMAND, value);
1304
1337
  }
1305
1338
 
1339
+ static VALUE set_enable_cleartext_plugin(VALUE self, VALUE value) {
1340
+ #ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
1341
+ return _mysql_client_options(self, MYSQL_ENABLE_CLEARTEXT_PLUGIN, value);
1342
+ #else
1343
+ rb_raise(cMysql2Error, "enable-cleartext-plugin is not available, you may need a newer MySQL client library");
1344
+ #endif
1345
+ }
1346
+
1306
1347
  static VALUE initialize_ext(VALUE self) {
1307
1348
  GET_CLIENT(self);
1308
1349
 
@@ -1363,6 +1404,7 @@ void init_mysql2_client() {
1363
1404
  rb_define_singleton_method(cMysql2Client, "info", rb_mysql_client_info, 0);
1364
1405
 
1365
1406
  rb_define_method(cMysql2Client, "close", rb_mysql_client_close, 0);
1407
+ rb_define_method(cMysql2Client, "closed?", rb_mysql_client_closed, 0);
1366
1408
  rb_define_method(cMysql2Client, "abandon_results!", rb_mysql_client_abandon_results, 0);
1367
1409
  rb_define_method(cMysql2Client, "escape", rb_mysql_client_real_escape, 1);
1368
1410
  rb_define_method(cMysql2Client, "server_info", rb_mysql_client_server_info, 0);
@@ -1398,6 +1440,7 @@ void init_mysql2_client() {
1398
1440
  rb_define_private_method(cMysql2Client, "init_command=", set_init_command, 1);
1399
1441
  rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
1400
1442
  rb_define_private_method(cMysql2Client, "ssl_mode=", rb_set_ssl_mode_option, 1);
1443
+ rb_define_private_method(cMysql2Client, "enable_cleartext_plugin=", set_enable_cleartext_plugin, 1);
1401
1444
  rb_define_private_method(cMysql2Client, "initialize_ext", initialize_ext, 0);
1402
1445
  rb_define_private_method(cMysql2Client, "connect", rb_connect, 7);
1403
1446
  rb_define_private_method(cMysql2Client, "_query", rb_query, 2);
@@ -1419,6 +1462,10 @@ void init_mysql2_client() {
1419
1462
  #ifdef CLIENT_LONG_PASSWORD
1420
1463
  rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
1421
1464
  LONG2NUM(CLIENT_LONG_PASSWORD));
1465
+ #else
1466
+ /* HACK because MariaDB 10.2 no longer defines this constant,
1467
+ * but we're using it in our default connection flags. */
1468
+ rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"), INT2NUM(0));
1422
1469
  #endif
1423
1470
 
1424
1471
  #ifdef CLIENT_FOUND_ROWS
@@ -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,17 @@ else
105
105
  asplode 'mysql.h'
106
106
  end
107
107
 
108
- add_ssl_defines([prefix, 'mysql.h'].compact.join('/'))
109
-
110
- %w(errmsg.h mysqld_error.h).each do |h|
111
- header = [prefix, h].compact.join '/'
108
+ %w(errmsg.h).each do |h|
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
+ have_const('MYSQL_ENABLE_CLEARTEXT_PLUGIN', mysql_h)
118
+
115
119
  # This is our wishlist. We use whichever flags work on the host.
116
120
  # -Wall and -Wextra are included by default.
117
121
  wishlist = [
@@ -11,14 +11,10 @@ void Init_mysql2(void);
11
11
 
12
12
  #ifdef HAVE_MYSQL_H
13
13
  #include <mysql.h>
14
- #include <mysql_com.h>
15
14
  #include <errmsg.h>
16
- #include <mysqld_error.h>
17
15
  #else
18
16
  #include <mysql/mysql.h>
19
- #include <mysql/mysql_com.h>
20
17
  #include <mysql/errmsg.h>
21
- #include <mysql/mysqld_error.h>
22
18
  #endif
23
19
 
24
20
  #ifdef HAVE_RUBY_ENCODING_H