mysql2 0.4.6 → 0.5.2
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 +4 -4
- data/README.md +82 -52
- data/examples/eventmachine.rb +0 -2
- data/examples/threaded.rb +2 -4
- data/ext/mysql2/client.c +171 -75
- data/ext/mysql2/client.h +2 -41
- data/ext/mysql2/extconf.rb +30 -23
- data/ext/mysql2/mysql2_ext.c +2 -1
- data/ext/mysql2/mysql2_ext.h +8 -8
- data/ext/mysql2/mysql_enc_to_ruby.h +10 -0
- data/ext/mysql2/result.c +24 -77
- data/ext/mysql2/result.h +2 -3
- data/ext/mysql2/statement.c +101 -73
- data/ext/mysql2/statement.h +0 -2
- data/ext/mysql2/wait_for_single_fd.h +2 -1
- data/lib/mysql2/client.rb +37 -31
- data/lib/mysql2/em.rb +2 -4
- data/lib/mysql2/error.rb +49 -20
- data/lib/mysql2/result.rb +2 -0
- data/lib/mysql2/statement.rb +3 -9
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +14 -15
- data/spec/em/em_spec.rb +6 -6
- data/spec/mysql2/client_spec.rb +300 -215
- data/spec/mysql2/error_spec.rb +3 -9
- data/spec/mysql2/result_spec.rb +124 -158
- data/spec/mysql2/statement_spec.rb +138 -185
- data/spec/spec_helper.rb +79 -61
- data/support/5072E1F5.asc +432 -0
- data/support/mysql_enc_to_ruby.rb +2 -2
- data/support/ruby_enc_to_mysql.rb +5 -5
- metadata +16 -14
data/ext/mysql2/client.c
CHANGED
@@ -15,30 +15,31 @@
|
|
15
15
|
#include "mysql_enc_name_to_ruby.h"
|
16
16
|
|
17
17
|
VALUE cMysql2Client;
|
18
|
-
extern VALUE mMysql2, cMysql2Error;
|
18
|
+
extern VALUE mMysql2, cMysql2Error, cMysql2TimeoutError;
|
19
19
|
static VALUE sym_id, sym_version, sym_header_version, sym_async, sym_symbolize_keys, sym_as, sym_array, sym_stream;
|
20
|
+
static VALUE sym_no_good_index_used, sym_no_index_used, sym_query_was_slow;
|
20
21
|
static ID intern_brackets, intern_merge, intern_merge_bang, intern_new_with_args;
|
21
22
|
|
22
|
-
#ifndef HAVE_RB_HASH_DUP
|
23
|
-
VALUE rb_hash_dup(VALUE other) {
|
24
|
-
return rb_funcall(rb_cHash, intern_brackets, 1, other);
|
25
|
-
}
|
26
|
-
#endif
|
27
|
-
|
28
23
|
#define REQUIRE_INITIALIZED(wrapper) \
|
29
24
|
if (!wrapper->initialized) { \
|
30
25
|
rb_raise(cMysql2Error, "MySQL client is not initialized"); \
|
31
26
|
}
|
32
27
|
|
28
|
+
#if defined(HAVE_MYSQL_NET_VIO) || defined(HAVE_ST_NET_VIO)
|
29
|
+
#define CONNECTED(wrapper) (wrapper->client->net.vio != NULL && wrapper->client->net.fd != -1)
|
30
|
+
#elif defined(HAVE_MYSQL_NET_PVIO) || defined(HAVE_ST_NET_PVIO)
|
31
|
+
#define CONNECTED(wrapper) (wrapper->client->net.pvio != NULL && wrapper->client->net.fd != -1)
|
32
|
+
#endif
|
33
|
+
|
33
34
|
#define REQUIRE_CONNECTED(wrapper) \
|
34
35
|
REQUIRE_INITIALIZED(wrapper) \
|
35
|
-
if (!wrapper
|
36
|
+
if (!CONNECTED(wrapper) && !wrapper->reconnect_enabled) { \
|
36
37
|
rb_raise(cMysql2Error, "MySQL client is not connected"); \
|
37
38
|
}
|
38
39
|
|
39
40
|
#define REQUIRE_NOT_CONNECTED(wrapper) \
|
40
41
|
REQUIRE_INITIALIZED(wrapper) \
|
41
|
-
if (wrapper
|
42
|
+
if (CONNECTED(wrapper)) { \
|
42
43
|
rb_raise(cMysql2Error, "MySQL connection is already open"); \
|
43
44
|
}
|
44
45
|
|
@@ -47,7 +48,9 @@ VALUE rb_hash_dup(VALUE other) {
|
|
47
48
|
* variable to use, but MYSQL_SERVER_VERSION gives the correct numbers when
|
48
49
|
* linking against the server itself
|
49
50
|
*/
|
50
|
-
#
|
51
|
+
#if defined(MARIADB_CLIENT_VERSION_STR)
|
52
|
+
#define MYSQL_LINK_VERSION MARIADB_CLIENT_VERSION_STR
|
53
|
+
#elif defined(LIBMYSQL_VERSION)
|
51
54
|
#define MYSQL_LINK_VERSION LIBMYSQL_VERSION
|
52
55
|
#else
|
53
56
|
#define MYSQL_LINK_VERSION MYSQL_SERVER_VERSION
|
@@ -107,14 +110,13 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
|
|
107
110
|
return Qnil;
|
108
111
|
}
|
109
112
|
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
|
110
|
-
GET_CLIENT(self);
|
113
|
+
GET_CLIENT(self);
|
111
114
|
int val = NUM2INT( setting );
|
112
115
|
if (version >= 50703 && version < 50711) {
|
113
116
|
if (val == SSL_MODE_DISABLED || val == SSL_MODE_REQUIRED) {
|
114
|
-
|
117
|
+
my_bool b = ( val == SSL_MODE_REQUIRED );
|
115
118
|
int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b );
|
116
119
|
return INT2NUM(result);
|
117
|
-
|
118
120
|
} else {
|
119
121
|
rb_warn( "MySQL client libraries between 5.7.3 and 5.7.10 only support SSL_MODE_DISABLED and SSL_MODE_REQUIRED" );
|
120
122
|
return Qnil;
|
@@ -122,7 +124,7 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
|
|
122
124
|
}
|
123
125
|
#endif
|
124
126
|
#ifdef FULL_SSL_MODE_SUPPORT
|
125
|
-
GET_CLIENT(self);
|
127
|
+
GET_CLIENT(self);
|
126
128
|
int val = NUM2INT( setting );
|
127
129
|
|
128
130
|
if (val != SSL_MODE_DISABLED && val != SSL_MODE_PREFERRED && val != SSL_MODE_REQUIRED && val != SSL_MODE_VERIFY_CA && val != SSL_MODE_VERIFY_IDENTITY) {
|
@@ -171,10 +173,8 @@ static VALUE rb_raise_mysql2_error(mysql_client_wrapper *wrapper) {
|
|
171
173
|
VALUE rb_sql_state = rb_tainted_str_new2(mysql_sqlstate(wrapper->client));
|
172
174
|
VALUE e;
|
173
175
|
|
174
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
175
176
|
rb_enc_associate(rb_error_msg, rb_utf8_encoding());
|
176
177
|
rb_enc_associate(rb_sql_state, rb_usascii_encoding());
|
177
|
-
#endif
|
178
178
|
|
179
179
|
e = rb_funcall(cMysql2Error, intern_new_with_args, 4,
|
180
180
|
rb_error_msg,
|
@@ -264,11 +264,10 @@ static VALUE invalidate_fd(int clientfd)
|
|
264
264
|
static void *nogvl_close(void *ptr) {
|
265
265
|
mysql_client_wrapper *wrapper = ptr;
|
266
266
|
|
267
|
-
if (wrapper->
|
267
|
+
if (!wrapper->closed) {
|
268
268
|
mysql_close(wrapper->client);
|
269
|
-
|
270
|
-
wrapper->
|
271
|
-
wrapper->connected = 0;
|
269
|
+
wrapper->closed = 1;
|
270
|
+
wrapper->reconnect_enabled = 0;
|
272
271
|
wrapper->active_thread = Qnil;
|
273
272
|
}
|
274
273
|
|
@@ -287,7 +286,7 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
|
|
287
286
|
|
288
287
|
if (wrapper->refcount == 0) {
|
289
288
|
#ifndef _WIN32
|
290
|
-
if (wrapper
|
289
|
+
if (CONNECTED(wrapper) && !wrapper->automatic_close) {
|
291
290
|
/* The client is being garbage collected while connected. Prevent
|
292
291
|
* mysql_close() from sending a mysql-QUIT or from calling shutdown() on
|
293
292
|
* the socket by invalidating it. invalidate_fd() will drop this
|
@@ -299,10 +298,12 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
|
|
299
298
|
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely\n");
|
300
299
|
close(wrapper->client->net.fd);
|
301
300
|
}
|
301
|
+
wrapper->client->net.fd = -1;
|
302
302
|
}
|
303
303
|
#endif
|
304
304
|
|
305
305
|
nogvl_close(wrapper);
|
306
|
+
xfree(wrapper->client);
|
306
307
|
xfree(wrapper);
|
307
308
|
}
|
308
309
|
}
|
@@ -317,9 +318,9 @@ static VALUE allocate(VALUE klass) {
|
|
317
318
|
wrapper->server_version = 0;
|
318
319
|
wrapper->reconnect_enabled = 0;
|
319
320
|
wrapper->connect_timeout = 0;
|
320
|
-
wrapper->connected = 0; /* means that a database connection is open */
|
321
321
|
wrapper->initialized = 0; /* means that that the wrapper is initialized */
|
322
322
|
wrapper->refcount = 1;
|
323
|
+
wrapper->closed = 0;
|
323
324
|
wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
|
324
325
|
|
325
326
|
return obj;
|
@@ -349,9 +350,7 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
|
|
349
350
|
return str;
|
350
351
|
} else {
|
351
352
|
rb_str = rb_str_new((const char*)newStr, newLen);
|
352
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
353
353
|
rb_enc_copy(rb_str, str);
|
354
|
-
#endif
|
355
354
|
xfree(newStr);
|
356
355
|
return rb_str;
|
357
356
|
}
|
@@ -378,9 +377,7 @@ static VALUE rb_mysql_info(VALUE self) {
|
|
378
377
|
}
|
379
378
|
|
380
379
|
rb_str = rb_str_new2(info);
|
381
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
382
380
|
rb_enc_associate(rb_str, rb_utf8_encoding());
|
383
|
-
#endif
|
384
381
|
|
385
382
|
return rb_str;
|
386
383
|
}
|
@@ -398,14 +395,25 @@ static VALUE rb_mysql_get_ssl_cipher(VALUE self)
|
|
398
395
|
}
|
399
396
|
|
400
397
|
rb_str = rb_str_new2(cipher);
|
401
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
402
398
|
rb_enc_associate(rb_str, rb_utf8_encoding());
|
403
|
-
#endif
|
404
399
|
|
405
400
|
return rb_str;
|
406
401
|
}
|
407
402
|
|
408
|
-
|
403
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
404
|
+
static int opt_connect_attr_add_i(VALUE key, VALUE value, VALUE arg)
|
405
|
+
{
|
406
|
+
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)arg;
|
407
|
+
rb_encoding *enc = rb_to_encoding(wrapper->encoding);
|
408
|
+
key = rb_str_export_to_enc(key, enc);
|
409
|
+
value = rb_str_export_to_enc(value, enc);
|
410
|
+
|
411
|
+
mysql_options4(wrapper->client, MYSQL_OPT_CONNECT_ATTR_ADD, StringValueCStr(key), StringValueCStr(value));
|
412
|
+
return ST_CONTINUE;
|
413
|
+
}
|
414
|
+
#endif
|
415
|
+
|
416
|
+
static VALUE rb_mysql_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags, VALUE conn_attrs) {
|
409
417
|
struct nogvl_connect_args args;
|
410
418
|
time_t start_time, end_time, elapsed_time, connect_timeout;
|
411
419
|
VALUE rv;
|
@@ -420,6 +428,11 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
420
428
|
args.mysql = wrapper->client;
|
421
429
|
args.client_flag = NUM2ULONG(flags);
|
422
430
|
|
431
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
432
|
+
mysql_options(wrapper->client, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
|
433
|
+
rb_hash_foreach(conn_attrs, opt_connect_attr_add_i, (VALUE)wrapper);
|
434
|
+
#endif
|
435
|
+
|
423
436
|
if (wrapper->connect_timeout)
|
424
437
|
time(&start_time);
|
425
438
|
rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0);
|
@@ -450,7 +463,6 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
450
463
|
}
|
451
464
|
|
452
465
|
wrapper->server_version = mysql_get_server_version(wrapper->client);
|
453
|
-
wrapper->connected = 1;
|
454
466
|
return self;
|
455
467
|
}
|
456
468
|
|
@@ -465,13 +477,23 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
465
477
|
static VALUE rb_mysql_client_close(VALUE self) {
|
466
478
|
GET_CLIENT(self);
|
467
479
|
|
468
|
-
if (wrapper->
|
480
|
+
if (wrapper->client) {
|
469
481
|
rb_thread_call_without_gvl(nogvl_close, wrapper, RUBY_UBF_IO, 0);
|
470
482
|
}
|
471
483
|
|
472
484
|
return Qnil;
|
473
485
|
}
|
474
486
|
|
487
|
+
/* call-seq:
|
488
|
+
* client.closed?
|
489
|
+
*
|
490
|
+
* @return [Boolean]
|
491
|
+
*/
|
492
|
+
static VALUE rb_mysql_client_closed(VALUE self) {
|
493
|
+
GET_CLIENT(self);
|
494
|
+
return CONNECTED(wrapper) ? Qfalse : Qtrue;
|
495
|
+
}
|
496
|
+
|
475
497
|
/*
|
476
498
|
* mysql_send_query is unlikely to block since most queries are small
|
477
499
|
* enough to fit in a socket buffer, but sometimes large UPDATE and
|
@@ -504,7 +526,7 @@ static VALUE do_send_query(void *args) {
|
|
504
526
|
*/
|
505
527
|
static void *nogvl_read_query_result(void *ptr) {
|
506
528
|
MYSQL * client = ptr;
|
507
|
-
|
529
|
+
my_bool res = mysql_read_query_result(client);
|
508
530
|
|
509
531
|
return (void *)(res == 0 ? Qtrue : Qfalse);
|
510
532
|
}
|
@@ -573,11 +595,14 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
|
|
573
595
|
return Qnil;
|
574
596
|
}
|
575
597
|
|
598
|
+
// Duplicate the options hash and put the copy in the Result object
|
576
599
|
current = rb_hash_dup(rb_iv_get(self, "@current_query_options"));
|
577
600
|
(void)RB_GC_GUARD(current);
|
578
601
|
Check_Type(current, T_HASH);
|
579
602
|
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
|
580
603
|
|
604
|
+
rb_mysql_set_server_query_flags(wrapper->client, resultObj);
|
605
|
+
|
581
606
|
return resultObj;
|
582
607
|
}
|
583
608
|
|
@@ -591,16 +616,16 @@ static VALUE disconnect_and_raise(VALUE self, VALUE error) {
|
|
591
616
|
GET_CLIENT(self);
|
592
617
|
|
593
618
|
wrapper->active_thread = Qnil;
|
594
|
-
wrapper->connected = 0;
|
595
619
|
|
596
620
|
/* Invalidate the MySQL socket to prevent further communication.
|
597
621
|
* The GC will come along later and call mysql_close to free it.
|
598
622
|
*/
|
599
|
-
if (wrapper
|
623
|
+
if (CONNECTED(wrapper)) {
|
600
624
|
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
|
601
625
|
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, closing unsafely\n");
|
602
626
|
close(wrapper->client->net.fd);
|
603
627
|
}
|
628
|
+
wrapper->client->net.fd = -1;
|
604
629
|
}
|
605
630
|
|
606
631
|
rb_exc_raise(error);
|
@@ -635,7 +660,7 @@ static VALUE do_query(void *args) {
|
|
635
660
|
retval = rb_wait_for_single_fd(async_args->fd, RB_WAITFD_IN, tvp);
|
636
661
|
|
637
662
|
if (retval == 0) {
|
638
|
-
rb_raise(
|
663
|
+
rb_raise(cMysql2TimeoutError, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
|
639
664
|
}
|
640
665
|
|
641
666
|
if (retval < 0) {
|
@@ -656,19 +681,21 @@ static VALUE disconnect_and_mark_inactive(VALUE self) {
|
|
656
681
|
|
657
682
|
/* Check if execution terminated while result was still being read. */
|
658
683
|
if (!NIL_P(wrapper->active_thread)) {
|
659
|
-
|
684
|
+
if (CONNECTED(wrapper)) {
|
685
|
+
/* Invalidate the MySQL socket to prevent further communication. */
|
660
686
|
#ifndef _WIN32
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
687
|
+
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
|
688
|
+
rb_warn("mysql2 failed to invalidate FD safely, closing unsafely\n");
|
689
|
+
close(wrapper->client->net.fd);
|
690
|
+
}
|
665
691
|
#else
|
666
|
-
|
692
|
+
close(wrapper->client->net.fd);
|
667
693
|
#endif
|
694
|
+
wrapper->client->net.fd = -1;
|
695
|
+
}
|
668
696
|
/* Skip mysql client check performed before command execution. */
|
669
697
|
wrapper->client->status = MYSQL_STATUS_READY;
|
670
698
|
wrapper->active_thread = Qnil;
|
671
|
-
wrapper->connected = 0;
|
672
699
|
}
|
673
700
|
|
674
701
|
return Qnil;
|
@@ -728,7 +755,7 @@ static VALUE rb_mysql_client_abandon_results(VALUE self) {
|
|
728
755
|
* Query the database with +sql+, with optional +options+. For the possible
|
729
756
|
* options, see default_query_options on the Mysql2::Client class.
|
730
757
|
*/
|
731
|
-
static VALUE
|
758
|
+
static VALUE rb_mysql_query(VALUE self, VALUE sql, VALUE current) {
|
732
759
|
#ifndef _WIN32
|
733
760
|
struct async_query_args async_args;
|
734
761
|
#endif
|
@@ -743,12 +770,8 @@ static VALUE rb_query(VALUE self, VALUE sql, VALUE current) {
|
|
743
770
|
rb_iv_set(self, "@current_query_options", current);
|
744
771
|
|
745
772
|
Check_Type(sql, T_STRING);
|
746
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
747
773
|
/* ensure the string is in the encoding the connection is expecting */
|
748
774
|
args.sql = rb_str_export_to_enc(sql, rb_to_encoding(wrapper->encoding));
|
749
|
-
#else
|
750
|
-
args.sql = sql;
|
751
|
-
#endif
|
752
775
|
args.sql_ptr = RSTRING_PTR(args.sql);
|
753
776
|
args.sql_len = RSTRING_LEN(args.sql);
|
754
777
|
args.wrapper = wrapper;
|
@@ -785,20 +808,16 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
785
808
|
unsigned char *newStr;
|
786
809
|
VALUE rb_str;
|
787
810
|
unsigned long newLen, oldLen;
|
788
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
789
811
|
rb_encoding *default_internal_enc;
|
790
812
|
rb_encoding *conn_enc;
|
791
|
-
#endif
|
792
813
|
GET_CLIENT(self);
|
793
814
|
|
794
815
|
REQUIRE_CONNECTED(wrapper);
|
795
816
|
Check_Type(str, T_STRING);
|
796
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
797
817
|
default_internal_enc = rb_default_internal_encoding();
|
798
818
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
799
819
|
/* ensure the string is in the encoding the connection is expecting */
|
800
820
|
str = rb_str_export_to_enc(str, conn_enc);
|
801
|
-
#endif
|
802
821
|
|
803
822
|
oldLen = RSTRING_LEN(str);
|
804
823
|
newStr = xmalloc(oldLen*2+1);
|
@@ -806,21 +825,17 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
806
825
|
newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, RSTRING_PTR(str), oldLen);
|
807
826
|
if (newLen == oldLen) {
|
808
827
|
/* no need to return a new ruby string if nothing changed */
|
809
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
810
828
|
if (default_internal_enc) {
|
811
829
|
str = rb_str_export_to_enc(str, default_internal_enc);
|
812
830
|
}
|
813
|
-
#endif
|
814
831
|
xfree(newStr);
|
815
832
|
return str;
|
816
833
|
} else {
|
817
834
|
rb_str = rb_str_new((const char*)newStr, newLen);
|
818
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
819
835
|
rb_enc_associate(rb_str, conn_enc);
|
820
836
|
if (default_internal_enc) {
|
821
837
|
rb_str = rb_str_export_to_enc(rb_str, default_internal_enc);
|
822
838
|
}
|
823
|
-
#endif
|
824
839
|
xfree(newStr);
|
825
840
|
return rb_str;
|
826
841
|
}
|
@@ -831,7 +846,7 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
|
831
846
|
const void *retval = NULL;
|
832
847
|
unsigned int intval = 0;
|
833
848
|
const char * charval = NULL;
|
834
|
-
|
849
|
+
my_bool boolval;
|
835
850
|
|
836
851
|
GET_CLIENT(self);
|
837
852
|
|
@@ -866,10 +881,12 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
|
866
881
|
retval = &boolval;
|
867
882
|
break;
|
868
883
|
|
884
|
+
#ifdef MYSQL_SECURE_AUTH
|
869
885
|
case MYSQL_SECURE_AUTH:
|
870
886
|
boolval = (value == Qfalse ? 0 : 1);
|
871
887
|
retval = &boolval;
|
872
888
|
break;
|
889
|
+
#endif
|
873
890
|
|
874
891
|
case MYSQL_READ_DEFAULT_FILE:
|
875
892
|
charval = (const char *)StringValueCStr(value);
|
@@ -886,6 +903,13 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
|
886
903
|
retval = charval;
|
887
904
|
break;
|
888
905
|
|
906
|
+
#ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
|
907
|
+
case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
|
908
|
+
boolval = (value == Qfalse ? 0 : 1);
|
909
|
+
retval = &boolval;
|
910
|
+
break;
|
911
|
+
#endif
|
912
|
+
|
889
913
|
default:
|
890
914
|
return Qfalse;
|
891
915
|
}
|
@@ -922,10 +946,8 @@ static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE klass) {
|
|
922
946
|
version = rb_str_new2(mysql_get_client_info());
|
923
947
|
header_version = rb_str_new2(MYSQL_LINK_VERSION);
|
924
948
|
|
925
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
926
949
|
rb_enc_associate(version, rb_usascii_encoding());
|
927
950
|
rb_enc_associate(header_version, rb_usascii_encoding());
|
928
|
-
#endif
|
929
951
|
|
930
952
|
rb_hash_aset(version_info, sym_id, LONG2NUM(mysql_get_client_version()));
|
931
953
|
rb_hash_aset(version_info, sym_version, version);
|
@@ -941,27 +963,21 @@ static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE klass) {
|
|
941
963
|
*/
|
942
964
|
static VALUE rb_mysql_client_server_info(VALUE self) {
|
943
965
|
VALUE version, server_info;
|
944
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
945
966
|
rb_encoding *default_internal_enc;
|
946
967
|
rb_encoding *conn_enc;
|
947
|
-
#endif
|
948
968
|
GET_CLIENT(self);
|
949
969
|
|
950
970
|
REQUIRE_CONNECTED(wrapper);
|
951
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
952
971
|
default_internal_enc = rb_default_internal_encoding();
|
953
972
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
954
|
-
#endif
|
955
973
|
|
956
974
|
version = rb_hash_new();
|
957
975
|
rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
|
958
976
|
server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
|
959
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
960
977
|
rb_enc_associate(server_info, conn_enc);
|
961
978
|
if (default_internal_enc) {
|
962
979
|
server_info = rb_str_export_to_enc(server_info, default_internal_enc);
|
963
980
|
}
|
964
|
-
#endif
|
965
981
|
rb_hash_aset(version, sym_version, server_info);
|
966
982
|
return version;
|
967
983
|
}
|
@@ -1075,13 +1091,30 @@ static void *nogvl_ping(void *ptr) {
|
|
1075
1091
|
static VALUE rb_mysql_client_ping(VALUE self) {
|
1076
1092
|
GET_CLIENT(self);
|
1077
1093
|
|
1078
|
-
if (!wrapper
|
1094
|
+
if (!CONNECTED(wrapper)) {
|
1079
1095
|
return Qfalse;
|
1080
1096
|
} else {
|
1081
1097
|
return (VALUE)rb_thread_call_without_gvl(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
|
1082
1098
|
}
|
1083
1099
|
}
|
1084
1100
|
|
1101
|
+
/* call-seq:
|
1102
|
+
* client.set_server_option(value)
|
1103
|
+
*
|
1104
|
+
* Enables or disables an option for the connection.
|
1105
|
+
* Read https://dev.mysql.com/doc/refman/5.7/en/mysql-set-server-option.html
|
1106
|
+
* for more information.
|
1107
|
+
*/
|
1108
|
+
static VALUE rb_mysql_client_set_server_option(VALUE self, VALUE value) {
|
1109
|
+
GET_CLIENT(self);
|
1110
|
+
|
1111
|
+
if (mysql_set_server_option(wrapper->client, NUM2INT(value)) == 0) {
|
1112
|
+
return Qtrue;
|
1113
|
+
} else {
|
1114
|
+
return Qfalse;
|
1115
|
+
}
|
1116
|
+
}
|
1117
|
+
|
1085
1118
|
/* call-seq:
|
1086
1119
|
* client.more_results?
|
1087
1120
|
*
|
@@ -1140,6 +1173,7 @@ static VALUE rb_mysql_client_store_result(VALUE self)
|
|
1140
1173
|
return Qnil;
|
1141
1174
|
}
|
1142
1175
|
|
1176
|
+
// Duplicate the options hash and put the copy in the Result object
|
1143
1177
|
current = rb_hash_dup(rb_iv_get(self, "@current_query_options"));
|
1144
1178
|
(void)RB_GC_GUARD(current);
|
1145
1179
|
Check_Type(current, T_HASH);
|
@@ -1148,7 +1182,6 @@ static VALUE rb_mysql_client_store_result(VALUE self)
|
|
1148
1182
|
return resultObj;
|
1149
1183
|
}
|
1150
1184
|
|
1151
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1152
1185
|
/* call-seq:
|
1153
1186
|
* client.encoding
|
1154
1187
|
*
|
@@ -1158,7 +1191,6 @@ static VALUE rb_mysql_client_encoding(VALUE self) {
|
|
1158
1191
|
GET_CLIENT(self);
|
1159
1192
|
return wrapper->encoding;
|
1160
1193
|
}
|
1161
|
-
#endif
|
1162
1194
|
|
1163
1195
|
/* call-seq:
|
1164
1196
|
* client.automatic_close?
|
@@ -1244,17 +1276,14 @@ static VALUE set_write_timeout(VALUE self, VALUE value) {
|
|
1244
1276
|
|
1245
1277
|
static VALUE set_charset_name(VALUE self, VALUE value) {
|
1246
1278
|
char *charset_name;
|
1247
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1248
1279
|
const struct mysql2_mysql_enc_name_to_rb_map *mysql2rb;
|
1249
1280
|
rb_encoding *enc;
|
1250
1281
|
VALUE rb_enc;
|
1251
|
-
#endif
|
1252
1282
|
GET_CLIENT(self);
|
1253
1283
|
|
1254
1284
|
Check_Type(value, T_STRING);
|
1255
1285
|
charset_name = RSTRING_PTR(value);
|
1256
1286
|
|
1257
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1258
1287
|
mysql2rb = mysql2_mysql_enc_name_to_rb(charset_name, (unsigned int)RSTRING_LEN(value));
|
1259
1288
|
if (mysql2rb == NULL || mysql2rb->rb_name == NULL) {
|
1260
1289
|
VALUE inspect = rb_inspect(value);
|
@@ -1264,7 +1293,6 @@ static VALUE set_charset_name(VALUE self, VALUE value) {
|
|
1264
1293
|
rb_enc = rb_enc_from_encoding(enc);
|
1265
1294
|
wrapper->encoding = rb_enc;
|
1266
1295
|
}
|
1267
|
-
#endif
|
1268
1296
|
|
1269
1297
|
if (mysql_options(wrapper->client, MYSQL_SET_CHARSET_NAME, charset_name)) {
|
1270
1298
|
/* TODO: warning - unable to set charset */
|
@@ -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);
|
@@ -1374,6 +1416,7 @@ void init_mysql2_client() {
|
|
1374
1416
|
rb_define_method(cMysql2Client, "thread_id", rb_mysql_client_thread_id, 0);
|
1375
1417
|
rb_define_method(cMysql2Client, "ping", rb_mysql_client_ping, 0);
|
1376
1418
|
rb_define_method(cMysql2Client, "select_db", rb_mysql_client_select_db, 1);
|
1419
|
+
rb_define_method(cMysql2Client, "set_server_option", rb_mysql_client_set_server_option, 1);
|
1377
1420
|
rb_define_method(cMysql2Client, "more_results?", rb_mysql_client_more_results, 0);
|
1378
1421
|
rb_define_method(cMysql2Client, "next_result", rb_mysql_client_next_result, 0);
|
1379
1422
|
rb_define_method(cMysql2Client, "store_result", rb_mysql_client_store_result, 0);
|
@@ -1383,9 +1426,7 @@ void init_mysql2_client() {
|
|
1383
1426
|
rb_define_method(cMysql2Client, "warning_count", rb_mysql_client_warning_count, 0);
|
1384
1427
|
rb_define_method(cMysql2Client, "query_info_string", rb_mysql_info, 0);
|
1385
1428
|
rb_define_method(cMysql2Client, "ssl_cipher", rb_mysql_get_ssl_cipher, 0);
|
1386
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1387
1429
|
rb_define_method(cMysql2Client, "encoding", rb_mysql_client_encoding, 0);
|
1388
|
-
#endif
|
1389
1430
|
|
1390
1431
|
rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
|
1391
1432
|
rb_define_private_method(cMysql2Client, "read_timeout=", set_read_timeout, 1);
|
@@ -1398,9 +1439,10 @@ void init_mysql2_client() {
|
|
1398
1439
|
rb_define_private_method(cMysql2Client, "init_command=", set_init_command, 1);
|
1399
1440
|
rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
|
1400
1441
|
rb_define_private_method(cMysql2Client, "ssl_mode=", rb_set_ssl_mode_option, 1);
|
1442
|
+
rb_define_private_method(cMysql2Client, "enable_cleartext_plugin=", set_enable_cleartext_plugin, 1);
|
1401
1443
|
rb_define_private_method(cMysql2Client, "initialize_ext", initialize_ext, 0);
|
1402
|
-
rb_define_private_method(cMysql2Client, "connect",
|
1403
|
-
rb_define_private_method(cMysql2Client, "_query",
|
1444
|
+
rb_define_private_method(cMysql2Client, "connect", rb_mysql_connect, 8);
|
1445
|
+
rb_define_private_method(cMysql2Client, "_query", rb_mysql_query, 2);
|
1404
1446
|
|
1405
1447
|
sym_id = ID2SYM(rb_intern("id"));
|
1406
1448
|
sym_version = ID2SYM(rb_intern("version"));
|
@@ -1411,6 +1453,10 @@ void init_mysql2_client() {
|
|
1411
1453
|
sym_array = ID2SYM(rb_intern("array"));
|
1412
1454
|
sym_stream = ID2SYM(rb_intern("stream"));
|
1413
1455
|
|
1456
|
+
sym_no_good_index_used = ID2SYM(rb_intern("no_good_index_used"));
|
1457
|
+
sym_no_index_used = ID2SYM(rb_intern("no_index_used"));
|
1458
|
+
sym_query_was_slow = ID2SYM(rb_intern("query_was_slow"));
|
1459
|
+
|
1414
1460
|
intern_brackets = rb_intern("[]");
|
1415
1461
|
intern_merge = rb_intern("merge");
|
1416
1462
|
intern_merge_bang = rb_intern("merge!");
|
@@ -1419,6 +1465,10 @@ void init_mysql2_client() {
|
|
1419
1465
|
#ifdef CLIENT_LONG_PASSWORD
|
1420
1466
|
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
|
1421
1467
|
LONG2NUM(CLIENT_LONG_PASSWORD));
|
1468
|
+
#else
|
1469
|
+
/* HACK because MariaDB 10.2 no longer defines this constant,
|
1470
|
+
* but we're using it in our default connection flags. */
|
1471
|
+
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"), INT2NUM(0));
|
1422
1472
|
#endif
|
1423
1473
|
|
1424
1474
|
#ifdef CLIENT_FOUND_ROWS
|
@@ -1496,6 +1546,16 @@ void init_mysql2_client() {
|
|
1496
1546
|
rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"), LONG2NUM(0));
|
1497
1547
|
#endif
|
1498
1548
|
|
1549
|
+
#ifdef HAVE_CONST_MYSQL_OPTION_MULTI_STATEMENTS_ON
|
1550
|
+
rb_const_set(cMysql2Client, rb_intern("OPTION_MULTI_STATEMENTS_ON"),
|
1551
|
+
LONG2NUM(MYSQL_OPTION_MULTI_STATEMENTS_ON));
|
1552
|
+
#endif
|
1553
|
+
|
1554
|
+
#ifdef HAVE_CONST_MYSQL_OPTION_MULTI_STATEMENTS_OFF
|
1555
|
+
rb_const_set(cMysql2Client, rb_intern("OPTION_MULTI_STATEMENTS_OFF"),
|
1556
|
+
LONG2NUM(MYSQL_OPTION_MULTI_STATEMENTS_OFF));
|
1557
|
+
#endif
|
1558
|
+
|
1499
1559
|
#ifdef CLIENT_MULTI_STATEMENTS
|
1500
1560
|
rb_const_set(cMysql2Client, rb_intern("MULTI_STATEMENTS"),
|
1501
1561
|
LONG2NUM(CLIENT_MULTI_STATEMENTS));
|
@@ -1526,6 +1586,16 @@ void init_mysql2_client() {
|
|
1526
1586
|
LONG2NUM(CLIENT_BASIC_FLAGS));
|
1527
1587
|
#endif
|
1528
1588
|
|
1589
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
1590
|
+
rb_const_set(cMysql2Client, rb_intern("CONNECT_ATTRS"),
|
1591
|
+
LONG2NUM(CLIENT_CONNECT_ATTRS));
|
1592
|
+
#else
|
1593
|
+
/* HACK because MySQL 5.5 and earlier don't define this constant,
|
1594
|
+
* but we're using it in our default connection flags. */
|
1595
|
+
rb_const_set(cMysql2Client, rb_intern("CONNECT_ATTRS"),
|
1596
|
+
INT2NUM(0));
|
1597
|
+
#endif
|
1598
|
+
|
1529
1599
|
#if defined(FULL_SSL_MODE_SUPPORT) // MySQL 5.7.11 and above
|
1530
1600
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
|
1531
1601
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_PREFERRED"), INT2NUM(SSL_MODE_PREFERRED));
|
@@ -1553,3 +1623,29 @@ void init_mysql2_client() {
|
|
1553
1623
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(0));
|
1554
1624
|
#endif
|
1555
1625
|
}
|
1626
|
+
|
1627
|
+
#define flag_to_bool(f) ((client->server_status & f) ? Qtrue : Qfalse)
|
1628
|
+
|
1629
|
+
void rb_mysql_set_server_query_flags(MYSQL *client, VALUE result) {
|
1630
|
+
VALUE server_flags = rb_hash_new();
|
1631
|
+
|
1632
|
+
#ifdef HAVE_CONST_SERVER_QUERY_NO_GOOD_INDEX_USED
|
1633
|
+
rb_hash_aset(server_flags, sym_no_good_index_used, flag_to_bool(SERVER_QUERY_NO_GOOD_INDEX_USED));
|
1634
|
+
#else
|
1635
|
+
rb_hash_aset(server_flags, sym_no_good_index_used, Qnil);
|
1636
|
+
#endif
|
1637
|
+
|
1638
|
+
#ifdef HAVE_CONST_SERVER_QUERY_NO_INDEX_USED
|
1639
|
+
rb_hash_aset(server_flags, sym_no_index_used, flag_to_bool(SERVER_QUERY_NO_INDEX_USED));
|
1640
|
+
#else
|
1641
|
+
rb_hash_aset(server_flags, sym_no_index_used, Qnil);
|
1642
|
+
#endif
|
1643
|
+
|
1644
|
+
#ifdef HAVE_CONST_SERVER_QUERY_WAS_SLOW
|
1645
|
+
rb_hash_aset(server_flags, sym_query_was_slow, flag_to_bool(SERVER_QUERY_WAS_SLOW));
|
1646
|
+
#else
|
1647
|
+
rb_hash_aset(server_flags, sym_query_was_slow, Qnil);
|
1648
|
+
#endif
|
1649
|
+
|
1650
|
+
rb_iv_set(result, "@server_flags", server_flags);
|
1651
|
+
}
|