mysql2 0.4.6 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
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
+ }