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.
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->connected && !wrapper->reconnect_enabled) { \
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->connected) { \
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
- #ifdef LIBMYSQL_VERSION
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
- bool b = ( val == SSL_MODE_REQUIRED );
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->client) {
267
+ if (!wrapper->closed) {
268
268
  mysql_close(wrapper->client);
269
- xfree(wrapper->client);
270
- wrapper->client = NULL;
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->connected && !wrapper->automatic_close) {
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
- static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags) {
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->connected) {
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
- bool res = mysql_read_query_result(client);
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->client) {
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(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
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
- /* Invalidate the MySQL socket to prevent further communication. */
684
+ if (CONNECTED(wrapper)) {
685
+ /* Invalidate the MySQL socket to prevent further communication. */
660
686
  #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
- }
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
- close(wrapper->client->net.fd);
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 rb_query(VALUE self, VALUE sql, VALUE current) {
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
- bool boolval;
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->connected) {
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", rb_connect, 7);
1403
- rb_define_private_method(cMysql2Client, "_query", rb_query, 2);
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
+ }