mysql2 0.4.10 → 0.5.6
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 +5 -5
- data/README.md +167 -48
- data/ext/mysql2/client.c +335 -108
- data/ext/mysql2/client.h +10 -41
- data/ext/mysql2/extconf.rb +84 -26
- data/ext/mysql2/mysql2_ext.c +8 -2
- data/ext/mysql2/mysql2_ext.h +21 -4
- data/ext/mysql2/mysql_enc_name_to_ruby.h +60 -55
- data/ext/mysql2/mysql_enc_to_ruby.h +79 -3
- data/ext/mysql2/result.c +298 -92
- data/ext/mysql2/result.h +3 -3
- data/ext/mysql2/statement.c +137 -81
- data/ext/mysql2/statement.h +0 -2
- data/ext/mysql2/wait_for_single_fd.h +2 -1
- data/lib/mysql2/client.rb +55 -28
- data/lib/mysql2/em.rb +2 -4
- data/lib/mysql2/error.rb +52 -22
- data/lib/mysql2/result.rb +2 -0
- data/lib/mysql2/statement.rb +3 -11
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +19 -15
- data/support/3A79BD29.asc +49 -0
- data/support/5072E1F5.asc +5 -5
- data/support/C74CD1D8.asc +104 -0
- data/support/mysql_enc_to_ruby.rb +9 -3
- data/support/ruby_enc_to_mysql.rb +8 -5
- metadata +19 -62
- data/examples/eventmachine.rb +0 -21
- data/examples/threaded.rb +0 -18
- data/spec/configuration.yml.example +0 -11
- data/spec/em/em_spec.rb +0 -136
- data/spec/my.cnf.example +0 -9
- data/spec/mysql2/client_spec.rb +0 -1039
- data/spec/mysql2/error_spec.rb +0 -82
- data/spec/mysql2/result_spec.rb +0 -545
- data/spec/mysql2/statement_spec.rb +0 -776
- data/spec/rcov.opts +0 -3
- data/spec/spec_helper.rb +0 -108
- data/spec/ssl/ca-cert.pem +0 -17
- data/spec/ssl/ca-key.pem +0 -27
- data/spec/ssl/ca.cnf +0 -22
- data/spec/ssl/cert.cnf +0 -22
- data/spec/ssl/client-cert.pem +0 -17
- data/spec/ssl/client-key.pem +0 -27
- data/spec/ssl/client-req.pem +0 -15
- data/spec/ssl/gen_certs.sh +0 -48
- data/spec/ssl/pkcs8-client-key.pem +0 -28
- data/spec/ssl/pkcs8-server-key.pem +0 -28
- data/spec/ssl/server-cert.pem +0 -17
- data/spec/ssl/server-key.pem +0 -27
- data/spec/ssl/server-req.pem +0 -15
- data/spec/test_data +0 -1
data/ext/mysql2/client.c
CHANGED
@@ -15,15 +15,11 @@
|
|
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
|
21
|
-
|
22
|
-
|
23
|
-
VALUE rb_hash_dup(VALUE other) {
|
24
|
-
return rb_funcall(rb_cHash, intern_brackets, 1, other);
|
25
|
-
}
|
26
|
-
#endif
|
20
|
+
static VALUE sym_no_good_index_used, sym_no_index_used, sym_query_was_slow;
|
21
|
+
static ID intern_brackets, intern_merge, intern_merge_bang, intern_new_with_args,
|
22
|
+
intern_current_query_options, intern_read_timeout;
|
27
23
|
|
28
24
|
#define REQUIRE_INITIALIZED(wrapper) \
|
29
25
|
if (!wrapper->initialized) { \
|
@@ -49,7 +45,7 @@ VALUE rb_hash_dup(VALUE other) {
|
|
49
45
|
}
|
50
46
|
|
51
47
|
/*
|
52
|
-
*
|
48
|
+
* compatibility with mysql-connector-c, where LIBMYSQL_VERSION is the correct
|
53
49
|
* variable to use, but MYSQL_SERVER_VERSION gives the correct numbers when
|
54
50
|
* linking against the server itself
|
55
51
|
*/
|
@@ -62,8 +58,23 @@ VALUE rb_hash_dup(VALUE other) {
|
|
62
58
|
#endif
|
63
59
|
|
64
60
|
/*
|
65
|
-
*
|
61
|
+
* mariadb-connector-c defines CLIENT_SESSION_TRACKING and SESSION_TRACK_TRANSACTION_TYPE
|
62
|
+
* while mysql-connector-c defines CLIENT_SESSION_TRACK and SESSION_TRACK_TRANSACTION_STATE
|
63
|
+
* This is a hack to take care of both clients.
|
64
|
+
*/
|
65
|
+
#if defined(CLIENT_SESSION_TRACK)
|
66
|
+
#elif defined(CLIENT_SESSION_TRACKING)
|
67
|
+
#define CLIENT_SESSION_TRACK CLIENT_SESSION_TRACKING
|
68
|
+
#define SESSION_TRACK_TRANSACTION_STATE SESSION_TRACK_TRANSACTION_TYPE
|
69
|
+
#endif
|
70
|
+
|
71
|
+
/*
|
72
|
+
* compatibility with mysql-connector-c 6.1.x, MySQL 5.7.3 - 5.7.10 & with MariaDB 10.x and later.
|
66
73
|
*/
|
74
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT
|
75
|
+
#define SSL_MODE_VERIFY_IDENTITY 5
|
76
|
+
#define HAVE_CONST_SSL_MODE_VERIFY_IDENTITY
|
77
|
+
#endif
|
67
78
|
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
|
68
79
|
#define SSL_MODE_DISABLED 1
|
69
80
|
#define SSL_MODE_REQUIRED 3
|
@@ -109,40 +120,80 @@ struct nogvl_select_db_args {
|
|
109
120
|
|
110
121
|
static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
|
111
122
|
unsigned long version = mysql_get_client_version();
|
123
|
+
const char *version_str = mysql_get_client_info();
|
112
124
|
|
113
|
-
|
114
|
-
|
125
|
+
/* Warn about versions that are known to be incomplete; these are pretty
|
126
|
+
* ancient, we want people to upgrade if they need SSL/TLS to work
|
127
|
+
*
|
128
|
+
* MySQL 5.x before 5.6.30 -- ssl_mode introduced but not fully working until 5.6.36)
|
129
|
+
* MySQL 5.7 before 5.7.3 -- ssl_mode introduced but not fully working until 5.7.11)
|
130
|
+
*/
|
131
|
+
if ((version >= 50000 && version < 50630) || (version >= 50700 && version < 50703)) {
|
132
|
+
rb_warn("Your mysql client library version %s does not support setting ssl_mode; full support comes with 5.6.36+, 5.7.11+, 8.0+", version_str);
|
115
133
|
return Qnil;
|
116
134
|
}
|
117
|
-
|
135
|
+
|
136
|
+
/* For these versions, map from the options we're exposing to Ruby to the constant available:
|
137
|
+
* ssl_mode: :verify_identity to MYSQL_OPT_SSL_VERIFY_SERVER_CERT = 1
|
138
|
+
* ssl_mode: :required to MYSQL_OPT_SSL_ENFORCE = 1
|
139
|
+
* ssl_mode: :disabled to MYSQL_OPT_SSL_ENFORCE = 0
|
140
|
+
*/
|
141
|
+
#if defined(HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT) || defined(HAVE_CONST_MYSQL_OPT_SSL_ENFORCE)
|
118
142
|
GET_CLIENT(self);
|
119
|
-
int val = NUM2INT(
|
120
|
-
|
143
|
+
int val = NUM2INT(setting);
|
144
|
+
|
145
|
+
/* Expected code path for MariaDB 10.x and MariaDB Connector/C 3.x
|
146
|
+
* Workaround code path for MySQL 5.7.3 - 5.7.10 and MySQL Connector/C 6.1.3 - 6.1.x
|
147
|
+
*/
|
148
|
+
if (version >= 100000 // MariaDB (all versions numbered 10.x)
|
149
|
+
|| (version >= 30000 && version < 40000) // MariaDB Connector/C (all versions numbered 3.x)
|
150
|
+
|| (version >= 50703 && version < 50711) // Workaround for MySQL 5.7.3 - 5.7.10
|
151
|
+
|| (version >= 60103 && version < 60200)) { // Workaround for MySQL Connector/C 6.1.3 - 6.1.x
|
152
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT
|
153
|
+
if (val == SSL_MODE_VERIFY_IDENTITY) {
|
154
|
+
my_bool b = 1;
|
155
|
+
int result = mysql_options(wrapper->client, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &b);
|
156
|
+
return INT2NUM(result);
|
157
|
+
}
|
158
|
+
#endif
|
159
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
|
121
160
|
if (val == SSL_MODE_DISABLED || val == SSL_MODE_REQUIRED) {
|
122
|
-
|
123
|
-
int result = mysql_options(
|
161
|
+
my_bool b = (val == SSL_MODE_REQUIRED);
|
162
|
+
int result = mysql_options(wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b);
|
124
163
|
return INT2NUM(result);
|
125
|
-
} else {
|
126
|
-
rb_warn( "MySQL client libraries between 5.7.3 and 5.7.10 only support SSL_MODE_DISABLED and SSL_MODE_REQUIRED" );
|
127
|
-
return Qnil;
|
128
164
|
}
|
165
|
+
#endif
|
166
|
+
rb_warn("Your mysql client library version %s does not support ssl_mode %d", version_str, val);
|
167
|
+
return Qnil;
|
168
|
+
} else {
|
169
|
+
rb_warn("Your mysql client library version %s does not support ssl_mode as expected", version_str);
|
170
|
+
return Qnil;
|
129
171
|
}
|
130
172
|
#endif
|
173
|
+
|
174
|
+
/* For other versions -- known to be MySQL 5.6.36+, 5.7.11+, 8.0+
|
175
|
+
* pass the value of the argument to MYSQL_OPT_SSL_MODE -- note the code
|
176
|
+
* mapping from atoms / constants is in the MySQL::Client Ruby class
|
177
|
+
*/
|
131
178
|
#ifdef FULL_SSL_MODE_SUPPORT
|
132
179
|
GET_CLIENT(self);
|
133
|
-
int val = NUM2INT(
|
180
|
+
int val = NUM2INT(setting);
|
134
181
|
|
135
182
|
if (val != SSL_MODE_DISABLED && val != SSL_MODE_PREFERRED && val != SSL_MODE_REQUIRED && val != SSL_MODE_VERIFY_CA && val != SSL_MODE_VERIFY_IDENTITY) {
|
136
183
|
rb_raise(cMysql2Error, "ssl_mode= takes DISABLED, PREFERRED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY, you passed: %d", val );
|
137
184
|
}
|
138
|
-
int result = mysql_options(
|
185
|
+
int result = mysql_options(wrapper->client, MYSQL_OPT_SSL_MODE, &val);
|
139
186
|
|
140
187
|
return INT2NUM(result);
|
141
188
|
#endif
|
189
|
+
|
190
|
+
// Warn if we get this far
|
142
191
|
#ifdef NO_SSL_MODE_SUPPORT
|
192
|
+
rb_warn("Your mysql client library does not support setting ssl_mode");
|
143
193
|
return Qnil;
|
144
194
|
#endif
|
145
195
|
}
|
196
|
+
|
146
197
|
/*
|
147
198
|
* non-blocking mysql_*() functions that we won't be wrapping since
|
148
199
|
* they do not appear to hit the network nor issue any interruptible
|
@@ -168,20 +219,54 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
|
|
168
219
|
static void rb_mysql_client_mark(void * wrapper) {
|
169
220
|
mysql_client_wrapper * w = wrapper;
|
170
221
|
if (w) {
|
171
|
-
|
172
|
-
|
222
|
+
rb_gc_mark_movable(w->encoding);
|
223
|
+
rb_gc_mark_movable(w->active_fiber);
|
224
|
+
}
|
225
|
+
}
|
226
|
+
|
227
|
+
/* this is called during GC */
|
228
|
+
static void rb_mysql_client_free(void *ptr) {
|
229
|
+
mysql_client_wrapper *wrapper = ptr;
|
230
|
+
decr_mysql2_client(wrapper);
|
231
|
+
}
|
232
|
+
|
233
|
+
static size_t rb_mysql_client_memsize(const void * wrapper) {
|
234
|
+
const mysql_client_wrapper * w = wrapper;
|
235
|
+
return sizeof(*w);
|
236
|
+
}
|
237
|
+
|
238
|
+
static void rb_mysql_client_compact(void * wrapper) {
|
239
|
+
mysql_client_wrapper * w = wrapper;
|
240
|
+
if (w) {
|
241
|
+
rb_mysql2_gc_location(w->encoding);
|
242
|
+
rb_mysql2_gc_location(w->active_fiber);
|
173
243
|
}
|
174
244
|
}
|
175
245
|
|
246
|
+
const rb_data_type_t rb_mysql_client_type = {
|
247
|
+
"rb_mysql_client",
|
248
|
+
{
|
249
|
+
rb_mysql_client_mark,
|
250
|
+
rb_mysql_client_free,
|
251
|
+
rb_mysql_client_memsize,
|
252
|
+
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
253
|
+
rb_mysql_client_compact,
|
254
|
+
#endif
|
255
|
+
},
|
256
|
+
0,
|
257
|
+
0,
|
258
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
259
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
260
|
+
#endif
|
261
|
+
};
|
262
|
+
|
176
263
|
static VALUE rb_raise_mysql2_error(mysql_client_wrapper *wrapper) {
|
177
264
|
VALUE rb_error_msg = rb_str_new2(mysql_error(wrapper->client));
|
178
|
-
VALUE rb_sql_state =
|
265
|
+
VALUE rb_sql_state = rb_str_new2(mysql_sqlstate(wrapper->client));
|
179
266
|
VALUE e;
|
180
267
|
|
181
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
182
268
|
rb_enc_associate(rb_error_msg, rb_utf8_encoding());
|
183
269
|
rb_enc_associate(rb_sql_state, rb_usascii_encoding());
|
184
|
-
#endif
|
185
270
|
|
186
271
|
e = rb_funcall(cMysql2Error, intern_new_with_args, 4,
|
187
272
|
rb_error_msg,
|
@@ -271,22 +356,16 @@ static VALUE invalidate_fd(int clientfd)
|
|
271
356
|
static void *nogvl_close(void *ptr) {
|
272
357
|
mysql_client_wrapper *wrapper = ptr;
|
273
358
|
|
274
|
-
if (!wrapper->closed) {
|
359
|
+
if (wrapper->initialized && !wrapper->closed) {
|
275
360
|
mysql_close(wrapper->client);
|
276
361
|
wrapper->closed = 1;
|
277
362
|
wrapper->reconnect_enabled = 0;
|
278
|
-
wrapper->
|
363
|
+
wrapper->active_fiber = Qnil;
|
279
364
|
}
|
280
365
|
|
281
366
|
return NULL;
|
282
367
|
}
|
283
368
|
|
284
|
-
/* this is called during GC */
|
285
|
-
static void rb_mysql_client_free(void *ptr) {
|
286
|
-
mysql_client_wrapper *wrapper = ptr;
|
287
|
-
decr_mysql2_client(wrapper);
|
288
|
-
}
|
289
|
-
|
290
369
|
void decr_mysql2_client(mysql_client_wrapper *wrapper)
|
291
370
|
{
|
292
371
|
wrapper->refcount--;
|
@@ -318,16 +397,20 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
|
|
318
397
|
static VALUE allocate(VALUE klass) {
|
319
398
|
VALUE obj;
|
320
399
|
mysql_client_wrapper * wrapper;
|
400
|
+
#ifdef NEW_TYPEDDATA_WRAPPER
|
401
|
+
obj = TypedData_Make_Struct(klass, mysql_client_wrapper, &rb_mysql_client_type, wrapper);
|
402
|
+
#else
|
321
403
|
obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
|
404
|
+
#endif
|
322
405
|
wrapper->encoding = Qnil;
|
323
|
-
wrapper->
|
406
|
+
wrapper->active_fiber = Qnil;
|
324
407
|
wrapper->automatic_close = 1;
|
325
408
|
wrapper->server_version = 0;
|
326
409
|
wrapper->reconnect_enabled = 0;
|
327
410
|
wrapper->connect_timeout = 0;
|
328
|
-
wrapper->initialized = 0; /*
|
411
|
+
wrapper->initialized = 0; /* will be set true after calling mysql_init */
|
412
|
+
wrapper->closed = 1; /* will be set false after calling mysql_real_connect */
|
329
413
|
wrapper->refcount = 1;
|
330
|
-
wrapper->closed = 0;
|
331
414
|
wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
|
332
415
|
|
333
416
|
return obj;
|
@@ -357,9 +440,7 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
|
|
357
440
|
return str;
|
358
441
|
} else {
|
359
442
|
rb_str = rb_str_new((const char*)newStr, newLen);
|
360
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
361
443
|
rb_enc_copy(rb_str, str);
|
362
|
-
#endif
|
363
444
|
xfree(newStr);
|
364
445
|
return rb_str;
|
365
446
|
}
|
@@ -386,9 +467,7 @@ static VALUE rb_mysql_info(VALUE self) {
|
|
386
467
|
}
|
387
468
|
|
388
469
|
rb_str = rb_str_new2(info);
|
389
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
390
470
|
rb_enc_associate(rb_str, rb_utf8_encoding());
|
391
|
-
#endif
|
392
471
|
|
393
472
|
return rb_str;
|
394
473
|
}
|
@@ -406,14 +485,25 @@ static VALUE rb_mysql_get_ssl_cipher(VALUE self)
|
|
406
485
|
}
|
407
486
|
|
408
487
|
rb_str = rb_str_new2(cipher);
|
409
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
410
488
|
rb_enc_associate(rb_str, rb_utf8_encoding());
|
411
|
-
#endif
|
412
489
|
|
413
490
|
return rb_str;
|
414
491
|
}
|
415
492
|
|
416
|
-
|
493
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
494
|
+
static int opt_connect_attr_add_i(VALUE key, VALUE value, VALUE arg)
|
495
|
+
{
|
496
|
+
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)arg;
|
497
|
+
rb_encoding *enc = rb_to_encoding(wrapper->encoding);
|
498
|
+
key = rb_str_export_to_enc(key, enc);
|
499
|
+
value = rb_str_export_to_enc(value, enc);
|
500
|
+
|
501
|
+
mysql_options4(wrapper->client, MYSQL_OPT_CONNECT_ATTR_ADD, StringValueCStr(key), StringValueCStr(value));
|
502
|
+
return ST_CONTINUE;
|
503
|
+
}
|
504
|
+
#endif
|
505
|
+
|
506
|
+
static VALUE rb_mysql_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags, VALUE conn_attrs) {
|
417
507
|
struct nogvl_connect_args args;
|
418
508
|
time_t start_time, end_time, elapsed_time, connect_timeout;
|
419
509
|
VALUE rv;
|
@@ -428,6 +518,11 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
428
518
|
args.mysql = wrapper->client;
|
429
519
|
args.client_flag = NUM2ULONG(flags);
|
430
520
|
|
521
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
522
|
+
mysql_options(wrapper->client, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
|
523
|
+
rb_hash_foreach(conn_attrs, opt_connect_attr_add_i, (VALUE)wrapper);
|
524
|
+
#endif
|
525
|
+
|
431
526
|
if (wrapper->connect_timeout)
|
432
527
|
time(&start_time);
|
433
528
|
rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0);
|
@@ -457,6 +552,7 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
457
552
|
rb_raise_mysql2_error(wrapper);
|
458
553
|
}
|
459
554
|
|
555
|
+
wrapper->closed = 0;
|
460
556
|
wrapper->server_version = mysql_get_server_version(wrapper->client);
|
461
557
|
return self;
|
462
558
|
}
|
@@ -503,12 +599,12 @@ static void *nogvl_send_query(void *ptr) {
|
|
503
599
|
return (void*)(rv == 0 ? Qtrue : Qfalse);
|
504
600
|
}
|
505
601
|
|
506
|
-
static VALUE do_send_query(
|
507
|
-
struct nogvl_send_query_args *query_args = args;
|
602
|
+
static VALUE do_send_query(VALUE args) {
|
603
|
+
struct nogvl_send_query_args *query_args = (void *)args;
|
508
604
|
mysql_client_wrapper *wrapper = query_args->wrapper;
|
509
|
-
if ((VALUE)rb_thread_call_without_gvl(nogvl_send_query,
|
605
|
+
if ((VALUE)rb_thread_call_without_gvl(nogvl_send_query, query_args, RUBY_UBF_IO, 0) == Qfalse) {
|
510
606
|
/* an error occurred, we're not active anymore */
|
511
|
-
wrapper->
|
607
|
+
wrapper->active_fiber = Qnil;
|
512
608
|
rb_raise_mysql2_error(wrapper);
|
513
609
|
}
|
514
610
|
return Qnil;
|
@@ -521,7 +617,7 @@ static VALUE do_send_query(void *args) {
|
|
521
617
|
*/
|
522
618
|
static void *nogvl_read_query_result(void *ptr) {
|
523
619
|
MYSQL * client = ptr;
|
524
|
-
|
620
|
+
my_bool res = mysql_read_query_result(client);
|
525
621
|
|
526
622
|
return (void *)(res == 0 ? Qtrue : Qfalse);
|
527
623
|
}
|
@@ -538,7 +634,7 @@ static void *nogvl_do_result(void *ptr, char use_result) {
|
|
538
634
|
|
539
635
|
/* once our result is stored off, this connection is
|
540
636
|
ready for another command to be issued */
|
541
|
-
wrapper->
|
637
|
+
wrapper->active_fiber = Qnil;
|
542
638
|
|
543
639
|
return result;
|
544
640
|
}
|
@@ -564,17 +660,17 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
|
|
564
660
|
GET_CLIENT(self);
|
565
661
|
|
566
662
|
/* if we're not waiting on a result, do nothing */
|
567
|
-
if (NIL_P(wrapper->
|
663
|
+
if (NIL_P(wrapper->active_fiber))
|
568
664
|
return Qnil;
|
569
665
|
|
570
666
|
REQUIRE_CONNECTED(wrapper);
|
571
667
|
if ((VALUE)rb_thread_call_without_gvl(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
|
572
668
|
/* an error occurred, mark this connection inactive */
|
573
|
-
wrapper->
|
669
|
+
wrapper->active_fiber = Qnil;
|
574
670
|
rb_raise_mysql2_error(wrapper);
|
575
671
|
}
|
576
672
|
|
577
|
-
is_streaming = rb_hash_aref(
|
673
|
+
is_streaming = rb_hash_aref(rb_ivar_get(self, intern_current_query_options), sym_stream);
|
578
674
|
if (is_streaming == Qtrue) {
|
579
675
|
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_use_result, wrapper, RUBY_UBF_IO, 0);
|
580
676
|
} else {
|
@@ -583,18 +679,21 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
|
|
583
679
|
|
584
680
|
if (result == NULL) {
|
585
681
|
if (mysql_errno(wrapper->client) != 0) {
|
586
|
-
wrapper->
|
682
|
+
wrapper->active_fiber = Qnil;
|
587
683
|
rb_raise_mysql2_error(wrapper);
|
588
684
|
}
|
589
685
|
/* no data and no error, so query was not a SELECT */
|
590
686
|
return Qnil;
|
591
687
|
}
|
592
688
|
|
593
|
-
|
689
|
+
// Duplicate the options hash and put the copy in the Result object
|
690
|
+
current = rb_hash_dup(rb_ivar_get(self, intern_current_query_options));
|
594
691
|
(void)RB_GC_GUARD(current);
|
595
692
|
Check_Type(current, T_HASH);
|
596
693
|
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
|
597
694
|
|
695
|
+
rb_mysql_set_server_query_flags(wrapper->client, resultObj);
|
696
|
+
|
598
697
|
return resultObj;
|
599
698
|
}
|
600
699
|
|
@@ -607,7 +706,7 @@ struct async_query_args {
|
|
607
706
|
static VALUE disconnect_and_raise(VALUE self, VALUE error) {
|
608
707
|
GET_CLIENT(self);
|
609
708
|
|
610
|
-
wrapper->
|
709
|
+
wrapper->active_fiber = Qnil;
|
611
710
|
|
612
711
|
/* Invalidate the MySQL socket to prevent further communication.
|
613
712
|
* The GC will come along later and call mysql_close to free it.
|
@@ -623,15 +722,15 @@ static VALUE disconnect_and_raise(VALUE self, VALUE error) {
|
|
623
722
|
rb_exc_raise(error);
|
624
723
|
}
|
625
724
|
|
626
|
-
static VALUE do_query(
|
627
|
-
struct async_query_args *async_args = args;
|
725
|
+
static VALUE do_query(VALUE args) {
|
726
|
+
struct async_query_args *async_args = (void *)args;
|
628
727
|
struct timeval tv;
|
629
728
|
struct timeval *tvp;
|
630
729
|
long int sec;
|
631
730
|
int retval;
|
632
731
|
VALUE read_timeout;
|
633
732
|
|
634
|
-
read_timeout =
|
733
|
+
read_timeout = rb_ivar_get(async_args->self, intern_read_timeout);
|
635
734
|
|
636
735
|
tvp = NULL;
|
637
736
|
if (!NIL_P(read_timeout)) {
|
@@ -652,7 +751,7 @@ static VALUE do_query(void *args) {
|
|
652
751
|
retval = rb_wait_for_single_fd(async_args->fd, RB_WAITFD_IN, tvp);
|
653
752
|
|
654
753
|
if (retval == 0) {
|
655
|
-
rb_raise(
|
754
|
+
rb_raise(cMysql2TimeoutError, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
|
656
755
|
}
|
657
756
|
|
658
757
|
if (retval < 0) {
|
@@ -672,7 +771,7 @@ static VALUE disconnect_and_mark_inactive(VALUE self) {
|
|
672
771
|
GET_CLIENT(self);
|
673
772
|
|
674
773
|
/* Check if execution terminated while result was still being read. */
|
675
|
-
if (!NIL_P(wrapper->
|
774
|
+
if (!NIL_P(wrapper->active_fiber)) {
|
676
775
|
if (CONNECTED(wrapper)) {
|
677
776
|
/* Invalidate the MySQL socket to prevent further communication. */
|
678
777
|
#ifndef _WIN32
|
@@ -687,24 +786,24 @@ static VALUE disconnect_and_mark_inactive(VALUE self) {
|
|
687
786
|
}
|
688
787
|
/* Skip mysql client check performed before command execution. */
|
689
788
|
wrapper->client->status = MYSQL_STATUS_READY;
|
690
|
-
wrapper->
|
789
|
+
wrapper->active_fiber = Qnil;
|
691
790
|
}
|
692
791
|
|
693
792
|
return Qnil;
|
694
793
|
}
|
695
794
|
|
696
|
-
void
|
697
|
-
VALUE
|
795
|
+
static void rb_mysql_client_set_active_fiber(VALUE self) {
|
796
|
+
VALUE fiber_current = rb_fiber_current();
|
698
797
|
GET_CLIENT(self);
|
699
798
|
|
700
799
|
// see if this connection is still waiting on a result from a previous query
|
701
|
-
if (NIL_P(wrapper->
|
800
|
+
if (NIL_P(wrapper->active_fiber)) {
|
702
801
|
// mark this connection active
|
703
|
-
wrapper->
|
704
|
-
} else if (wrapper->
|
802
|
+
wrapper->active_fiber = fiber_current;
|
803
|
+
} else if (wrapper->active_fiber == fiber_current) {
|
705
804
|
rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
|
706
805
|
} else {
|
707
|
-
VALUE inspect = rb_inspect(wrapper->
|
806
|
+
VALUE inspect = rb_inspect(wrapper->active_fiber);
|
708
807
|
const char *thr = StringValueCStr(inspect);
|
709
808
|
|
710
809
|
rb_raise(cMysql2Error, "This connection is in use by: %s", thr);
|
@@ -747,7 +846,7 @@ static VALUE rb_mysql_client_abandon_results(VALUE self) {
|
|
747
846
|
* Query the database with +sql+, with optional +options+. For the possible
|
748
847
|
* options, see default_query_options on the Mysql2::Client class.
|
749
848
|
*/
|
750
|
-
static VALUE
|
849
|
+
static VALUE rb_mysql_query(VALUE self, VALUE sql, VALUE current) {
|
751
850
|
#ifndef _WIN32
|
752
851
|
struct async_query_args async_args;
|
753
852
|
#endif
|
@@ -759,23 +858,20 @@ static VALUE rb_query(VALUE self, VALUE sql, VALUE current) {
|
|
759
858
|
|
760
859
|
(void)RB_GC_GUARD(current);
|
761
860
|
Check_Type(current, T_HASH);
|
762
|
-
|
861
|
+
rb_ivar_set(self, intern_current_query_options, current);
|
763
862
|
|
764
863
|
Check_Type(sql, T_STRING);
|
765
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
766
864
|
/* ensure the string is in the encoding the connection is expecting */
|
767
865
|
args.sql = rb_str_export_to_enc(sql, rb_to_encoding(wrapper->encoding));
|
768
|
-
#else
|
769
|
-
args.sql = sql;
|
770
|
-
#endif
|
771
866
|
args.sql_ptr = RSTRING_PTR(args.sql);
|
772
867
|
args.sql_len = RSTRING_LEN(args.sql);
|
773
868
|
args.wrapper = wrapper;
|
774
869
|
|
775
|
-
|
870
|
+
rb_mysql_client_set_active_fiber(self);
|
776
871
|
|
777
872
|
#ifndef _WIN32
|
778
873
|
rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);
|
874
|
+
(void)RB_GC_GUARD(sql);
|
779
875
|
|
780
876
|
if (rb_hash_aref(current, sym_async) == Qtrue) {
|
781
877
|
return Qnil;
|
@@ -788,7 +884,8 @@ static VALUE rb_query(VALUE self, VALUE sql, VALUE current) {
|
|
788
884
|
return rb_ensure(rb_mysql_client_async_result, self, disconnect_and_mark_inactive, self);
|
789
885
|
}
|
790
886
|
#else
|
791
|
-
do_send_query(&args);
|
887
|
+
do_send_query((VALUE)&args);
|
888
|
+
(void)RB_GC_GUARD(sql);
|
792
889
|
|
793
890
|
/* this will just block until the result is ready */
|
794
891
|
return rb_ensure(rb_mysql_client_async_result, self, disconnect_and_mark_inactive, self);
|
@@ -804,20 +901,16 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
804
901
|
unsigned char *newStr;
|
805
902
|
VALUE rb_str;
|
806
903
|
unsigned long newLen, oldLen;
|
807
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
808
904
|
rb_encoding *default_internal_enc;
|
809
905
|
rb_encoding *conn_enc;
|
810
|
-
#endif
|
811
906
|
GET_CLIENT(self);
|
812
907
|
|
813
908
|
REQUIRE_CONNECTED(wrapper);
|
814
909
|
Check_Type(str, T_STRING);
|
815
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
816
910
|
default_internal_enc = rb_default_internal_encoding();
|
817
911
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
818
912
|
/* ensure the string is in the encoding the connection is expecting */
|
819
913
|
str = rb_str_export_to_enc(str, conn_enc);
|
820
|
-
#endif
|
821
914
|
|
822
915
|
oldLen = RSTRING_LEN(str);
|
823
916
|
newStr = xmalloc(oldLen*2+1);
|
@@ -825,21 +918,17 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
825
918
|
newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, RSTRING_PTR(str), oldLen);
|
826
919
|
if (newLen == oldLen) {
|
827
920
|
/* no need to return a new ruby string if nothing changed */
|
828
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
829
921
|
if (default_internal_enc) {
|
830
922
|
str = rb_str_export_to_enc(str, default_internal_enc);
|
831
923
|
}
|
832
|
-
#endif
|
833
924
|
xfree(newStr);
|
834
925
|
return str;
|
835
926
|
} else {
|
836
927
|
rb_str = rb_str_new((const char*)newStr, newLen);
|
837
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
838
928
|
rb_enc_associate(rb_str, conn_enc);
|
839
929
|
if (default_internal_enc) {
|
840
930
|
rb_str = rb_str_export_to_enc(rb_str, default_internal_enc);
|
841
931
|
}
|
842
|
-
#endif
|
843
932
|
xfree(newStr);
|
844
933
|
return rb_str;
|
845
934
|
}
|
@@ -850,7 +939,7 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
|
850
939
|
const void *retval = NULL;
|
851
940
|
unsigned int intval = 0;
|
852
941
|
const char * charval = NULL;
|
853
|
-
|
942
|
+
my_bool boolval;
|
854
943
|
|
855
944
|
GET_CLIENT(self);
|
856
945
|
|
@@ -907,6 +996,13 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
|
907
996
|
retval = charval;
|
908
997
|
break;
|
909
998
|
|
999
|
+
#ifdef HAVE_MYSQL_DEFAULT_AUTH
|
1000
|
+
case MYSQL_DEFAULT_AUTH:
|
1001
|
+
charval = (const char *)StringValueCStr(value);
|
1002
|
+
retval = charval;
|
1003
|
+
break;
|
1004
|
+
#endif
|
1005
|
+
|
910
1006
|
#ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
|
911
1007
|
case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
|
912
1008
|
boolval = (value == Qfalse ? 0 : 1);
|
@@ -950,10 +1046,8 @@ static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE klass) {
|
|
950
1046
|
version = rb_str_new2(mysql_get_client_info());
|
951
1047
|
header_version = rb_str_new2(MYSQL_LINK_VERSION);
|
952
1048
|
|
953
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
954
1049
|
rb_enc_associate(version, rb_usascii_encoding());
|
955
1050
|
rb_enc_associate(header_version, rb_usascii_encoding());
|
956
|
-
#endif
|
957
1051
|
|
958
1052
|
rb_hash_aset(version_info, sym_id, LONG2NUM(mysql_get_client_version()));
|
959
1053
|
rb_hash_aset(version_info, sym_version, version);
|
@@ -969,27 +1063,21 @@ static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE klass) {
|
|
969
1063
|
*/
|
970
1064
|
static VALUE rb_mysql_client_server_info(VALUE self) {
|
971
1065
|
VALUE version, server_info;
|
972
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
973
1066
|
rb_encoding *default_internal_enc;
|
974
1067
|
rb_encoding *conn_enc;
|
975
|
-
#endif
|
976
1068
|
GET_CLIENT(self);
|
977
1069
|
|
978
1070
|
REQUIRE_CONNECTED(wrapper);
|
979
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
980
1071
|
default_internal_enc = rb_default_internal_encoding();
|
981
1072
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
982
|
-
#endif
|
983
1073
|
|
984
1074
|
version = rb_hash_new();
|
985
1075
|
rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
|
986
1076
|
server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
|
987
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
988
1077
|
rb_enc_associate(server_info, conn_enc);
|
989
1078
|
if (default_internal_enc) {
|
990
1079
|
server_info = rb_str_export_to_enc(server_info, default_internal_enc);
|
991
1080
|
}
|
992
|
-
#endif
|
993
1081
|
rb_hash_aset(version, sym_version, server_info);
|
994
1082
|
return version;
|
995
1083
|
}
|
@@ -1023,6 +1111,36 @@ static VALUE rb_mysql_client_last_id(VALUE self) {
|
|
1023
1111
|
return ULL2NUM(mysql_insert_id(wrapper->client));
|
1024
1112
|
}
|
1025
1113
|
|
1114
|
+
/* call-seq:
|
1115
|
+
* client.session_track
|
1116
|
+
*
|
1117
|
+
* Returns information about changes to the session state on the server.
|
1118
|
+
*/
|
1119
|
+
static VALUE rb_mysql_client_session_track(VALUE self, VALUE type) {
|
1120
|
+
#ifdef CLIENT_SESSION_TRACK
|
1121
|
+
const char *data;
|
1122
|
+
size_t length;
|
1123
|
+
my_ulonglong retVal;
|
1124
|
+
GET_CLIENT(self);
|
1125
|
+
|
1126
|
+
REQUIRE_CONNECTED(wrapper);
|
1127
|
+
retVal = mysql_session_track_get_first(wrapper->client, NUM2INT(type), &data, &length);
|
1128
|
+
if (retVal != 0) {
|
1129
|
+
return Qnil;
|
1130
|
+
}
|
1131
|
+
VALUE rbAry = rb_ary_new();
|
1132
|
+
VALUE rbFirst = rb_str_new(data, length);
|
1133
|
+
rb_ary_push(rbAry, rbFirst);
|
1134
|
+
while(mysql_session_track_get_next(wrapper->client, NUM2INT(type), &data, &length) == 0) {
|
1135
|
+
VALUE rbNext = rb_str_new(data, length);
|
1136
|
+
rb_ary_push(rbAry, rbNext);
|
1137
|
+
}
|
1138
|
+
return rbAry;
|
1139
|
+
#else
|
1140
|
+
return Qnil;
|
1141
|
+
#endif
|
1142
|
+
}
|
1143
|
+
|
1026
1144
|
/* call-seq:
|
1027
1145
|
* client.affected_rows
|
1028
1146
|
*
|
@@ -1110,6 +1228,23 @@ static VALUE rb_mysql_client_ping(VALUE self) {
|
|
1110
1228
|
}
|
1111
1229
|
}
|
1112
1230
|
|
1231
|
+
/* call-seq:
|
1232
|
+
* client.set_server_option(value)
|
1233
|
+
*
|
1234
|
+
* Enables or disables an option for the connection.
|
1235
|
+
* Read https://dev.mysql.com/doc/refman/5.7/en/mysql-set-server-option.html
|
1236
|
+
* for more information.
|
1237
|
+
*/
|
1238
|
+
static VALUE rb_mysql_client_set_server_option(VALUE self, VALUE value) {
|
1239
|
+
GET_CLIENT(self);
|
1240
|
+
|
1241
|
+
if (mysql_set_server_option(wrapper->client, NUM2INT(value)) == 0) {
|
1242
|
+
return Qtrue;
|
1243
|
+
} else {
|
1244
|
+
return Qfalse;
|
1245
|
+
}
|
1246
|
+
}
|
1247
|
+
|
1113
1248
|
/* call-seq:
|
1114
1249
|
* client.more_results?
|
1115
1250
|
*
|
@@ -1168,7 +1303,8 @@ static VALUE rb_mysql_client_store_result(VALUE self)
|
|
1168
1303
|
return Qnil;
|
1169
1304
|
}
|
1170
1305
|
|
1171
|
-
|
1306
|
+
// Duplicate the options hash and put the copy in the Result object
|
1307
|
+
current = rb_hash_dup(rb_ivar_get(self, intern_current_query_options));
|
1172
1308
|
(void)RB_GC_GUARD(current);
|
1173
1309
|
Check_Type(current, T_HASH);
|
1174
1310
|
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
|
@@ -1176,7 +1312,6 @@ static VALUE rb_mysql_client_store_result(VALUE self)
|
|
1176
1312
|
return resultObj;
|
1177
1313
|
}
|
1178
1314
|
|
1179
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1180
1315
|
/* call-seq:
|
1181
1316
|
* client.encoding
|
1182
1317
|
*
|
@@ -1186,7 +1321,6 @@ static VALUE rb_mysql_client_encoding(VALUE self) {
|
|
1186
1321
|
GET_CLIENT(self);
|
1187
1322
|
return wrapper->encoding;
|
1188
1323
|
}
|
1189
|
-
#endif
|
1190
1324
|
|
1191
1325
|
/* call-seq:
|
1192
1326
|
* client.automatic_close?
|
@@ -1256,7 +1390,7 @@ static VALUE set_read_timeout(VALUE self, VALUE value) {
|
|
1256
1390
|
/* Set the instance variable here even though _mysql_client_options
|
1257
1391
|
might not succeed, because the timeout is used in other ways
|
1258
1392
|
elsewhere */
|
1259
|
-
|
1393
|
+
rb_ivar_set(self, intern_read_timeout, value);
|
1260
1394
|
return _mysql_client_options(self, MYSQL_OPT_READ_TIMEOUT, value);
|
1261
1395
|
}
|
1262
1396
|
|
@@ -1272,17 +1406,14 @@ static VALUE set_write_timeout(VALUE self, VALUE value) {
|
|
1272
1406
|
|
1273
1407
|
static VALUE set_charset_name(VALUE self, VALUE value) {
|
1274
1408
|
char *charset_name;
|
1275
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1276
1409
|
const struct mysql2_mysql_enc_name_to_rb_map *mysql2rb;
|
1277
1410
|
rb_encoding *enc;
|
1278
1411
|
VALUE rb_enc;
|
1279
|
-
#endif
|
1280
1412
|
GET_CLIENT(self);
|
1281
1413
|
|
1282
1414
|
Check_Type(value, T_STRING);
|
1283
1415
|
charset_name = RSTRING_PTR(value);
|
1284
1416
|
|
1285
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1286
1417
|
mysql2rb = mysql2_mysql_enc_name_to_rb(charset_name, (unsigned int)RSTRING_LEN(value));
|
1287
1418
|
if (mysql2rb == NULL || mysql2rb->rb_name == NULL) {
|
1288
1419
|
VALUE inspect = rb_inspect(value);
|
@@ -1292,7 +1423,6 @@ static VALUE set_charset_name(VALUE self, VALUE value) {
|
|
1292
1423
|
rb_enc = rb_enc_from_encoding(enc);
|
1293
1424
|
wrapper->encoding = rb_enc;
|
1294
1425
|
}
|
1295
|
-
#endif
|
1296
1426
|
|
1297
1427
|
if (mysql_options(wrapper->client, MYSQL_SET_CHARSET_NAME, charset_name)) {
|
1298
1428
|
/* TODO: warning - unable to set charset */
|
@@ -1305,12 +1435,31 @@ static VALUE set_charset_name(VALUE self, VALUE value) {
|
|
1305
1435
|
static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE capath, VALUE cipher) {
|
1306
1436
|
GET_CLIENT(self);
|
1307
1437
|
|
1438
|
+
#ifdef HAVE_MYSQL_SSL_SET
|
1308
1439
|
mysql_ssl_set(wrapper->client,
|
1309
1440
|
NIL_P(key) ? NULL : StringValueCStr(key),
|
1310
1441
|
NIL_P(cert) ? NULL : StringValueCStr(cert),
|
1311
1442
|
NIL_P(ca) ? NULL : StringValueCStr(ca),
|
1312
1443
|
NIL_P(capath) ? NULL : StringValueCStr(capath),
|
1313
1444
|
NIL_P(cipher) ? NULL : StringValueCStr(cipher));
|
1445
|
+
#else
|
1446
|
+
/* mysql 8.3 does not provide mysql_ssl_set */
|
1447
|
+
if (!NIL_P(key)) {
|
1448
|
+
mysql_options(wrapper->client, MYSQL_OPT_SSL_KEY, StringValueCStr(key));
|
1449
|
+
}
|
1450
|
+
if (!NIL_P(cert)) {
|
1451
|
+
mysql_options(wrapper->client, MYSQL_OPT_SSL_CERT, StringValueCStr(cert));
|
1452
|
+
}
|
1453
|
+
if (!NIL_P(ca)) {
|
1454
|
+
mysql_options(wrapper->client, MYSQL_OPT_SSL_CA, StringValueCStr(ca));
|
1455
|
+
}
|
1456
|
+
if (!NIL_P(capath)) {
|
1457
|
+
mysql_options(wrapper->client, MYSQL_OPT_SSL_CAPATH, StringValueCStr(capath));
|
1458
|
+
}
|
1459
|
+
if (!NIL_P(cipher)) {
|
1460
|
+
mysql_options(wrapper->client, MYSQL_OPT_SSL_CIPHER, StringValueCStr(cipher));
|
1461
|
+
}
|
1462
|
+
#endif
|
1314
1463
|
|
1315
1464
|
return self;
|
1316
1465
|
}
|
@@ -1336,6 +1485,14 @@ static VALUE set_init_command(VALUE self, VALUE value) {
|
|
1336
1485
|
return _mysql_client_options(self, MYSQL_INIT_COMMAND, value);
|
1337
1486
|
}
|
1338
1487
|
|
1488
|
+
static VALUE set_default_auth(VALUE self, VALUE value) {
|
1489
|
+
#ifdef HAVE_MYSQL_DEFAULT_AUTH
|
1490
|
+
return _mysql_client_options(self, MYSQL_DEFAULT_AUTH, value);
|
1491
|
+
#else
|
1492
|
+
rb_raise(cMysql2Error, "pluggable authentication is not available, you may need a newer MySQL client library");
|
1493
|
+
#endif
|
1494
|
+
}
|
1495
|
+
|
1339
1496
|
static VALUE set_enable_cleartext_plugin(VALUE self, VALUE value) {
|
1340
1497
|
#ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
|
1341
1498
|
return _mysql_client_options(self, MYSQL_ENABLE_CLEARTEXT_PLUGIN, value);
|
@@ -1397,6 +1554,7 @@ void init_mysql2_client() {
|
|
1397
1554
|
mMysql2 = rb_define_module("Mysql2"); Teach RDoc about Mysql2 constant.
|
1398
1555
|
#endif
|
1399
1556
|
cMysql2Client = rb_define_class_under(mMysql2, "Client", rb_cObject);
|
1557
|
+
rb_global_variable(&cMysql2Client);
|
1400
1558
|
|
1401
1559
|
rb_define_alloc_func(cMysql2Client, allocate);
|
1402
1560
|
|
@@ -1416,6 +1574,7 @@ void init_mysql2_client() {
|
|
1416
1574
|
rb_define_method(cMysql2Client, "thread_id", rb_mysql_client_thread_id, 0);
|
1417
1575
|
rb_define_method(cMysql2Client, "ping", rb_mysql_client_ping, 0);
|
1418
1576
|
rb_define_method(cMysql2Client, "select_db", rb_mysql_client_select_db, 1);
|
1577
|
+
rb_define_method(cMysql2Client, "set_server_option", rb_mysql_client_set_server_option, 1);
|
1419
1578
|
rb_define_method(cMysql2Client, "more_results?", rb_mysql_client_more_results, 0);
|
1420
1579
|
rb_define_method(cMysql2Client, "next_result", rb_mysql_client_next_result, 0);
|
1421
1580
|
rb_define_method(cMysql2Client, "store_result", rb_mysql_client_store_result, 0);
|
@@ -1425,9 +1584,8 @@ void init_mysql2_client() {
|
|
1425
1584
|
rb_define_method(cMysql2Client, "warning_count", rb_mysql_client_warning_count, 0);
|
1426
1585
|
rb_define_method(cMysql2Client, "query_info_string", rb_mysql_info, 0);
|
1427
1586
|
rb_define_method(cMysql2Client, "ssl_cipher", rb_mysql_get_ssl_cipher, 0);
|
1428
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1429
1587
|
rb_define_method(cMysql2Client, "encoding", rb_mysql_client_encoding, 0);
|
1430
|
-
|
1588
|
+
rb_define_method(cMysql2Client, "session_track", rb_mysql_client_session_track, 1);
|
1431
1589
|
|
1432
1590
|
rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
|
1433
1591
|
rb_define_private_method(cMysql2Client, "read_timeout=", set_read_timeout, 1);
|
@@ -1438,12 +1596,13 @@ void init_mysql2_client() {
|
|
1438
1596
|
rb_define_private_method(cMysql2Client, "default_file=", set_read_default_file, 1);
|
1439
1597
|
rb_define_private_method(cMysql2Client, "default_group=", set_read_default_group, 1);
|
1440
1598
|
rb_define_private_method(cMysql2Client, "init_command=", set_init_command, 1);
|
1599
|
+
rb_define_private_method(cMysql2Client, "default_auth=", set_default_auth, 1);
|
1441
1600
|
rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
|
1442
1601
|
rb_define_private_method(cMysql2Client, "ssl_mode=", rb_set_ssl_mode_option, 1);
|
1443
1602
|
rb_define_private_method(cMysql2Client, "enable_cleartext_plugin=", set_enable_cleartext_plugin, 1);
|
1444
1603
|
rb_define_private_method(cMysql2Client, "initialize_ext", initialize_ext, 0);
|
1445
|
-
rb_define_private_method(cMysql2Client, "connect",
|
1446
|
-
rb_define_private_method(cMysql2Client, "_query",
|
1604
|
+
rb_define_private_method(cMysql2Client, "connect", rb_mysql_connect, 8);
|
1605
|
+
rb_define_private_method(cMysql2Client, "_query", rb_mysql_query, 2);
|
1447
1606
|
|
1448
1607
|
sym_id = ID2SYM(rb_intern("id"));
|
1449
1608
|
sym_version = ID2SYM(rb_intern("version"));
|
@@ -1454,10 +1613,16 @@ void init_mysql2_client() {
|
|
1454
1613
|
sym_array = ID2SYM(rb_intern("array"));
|
1455
1614
|
sym_stream = ID2SYM(rb_intern("stream"));
|
1456
1615
|
|
1616
|
+
sym_no_good_index_used = ID2SYM(rb_intern("no_good_index_used"));
|
1617
|
+
sym_no_index_used = ID2SYM(rb_intern("no_index_used"));
|
1618
|
+
sym_query_was_slow = ID2SYM(rb_intern("query_was_slow"));
|
1619
|
+
|
1457
1620
|
intern_brackets = rb_intern("[]");
|
1458
1621
|
intern_merge = rb_intern("merge");
|
1459
1622
|
intern_merge_bang = rb_intern("merge!");
|
1460
1623
|
intern_new_with_args = rb_intern("new_with_args");
|
1624
|
+
intern_current_query_options = rb_intern("@current_query_options");
|
1625
|
+
intern_read_timeout = rb_intern("@read_timeout");
|
1461
1626
|
|
1462
1627
|
#ifdef CLIENT_LONG_PASSWORD
|
1463
1628
|
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
|
@@ -1543,6 +1708,16 @@ void init_mysql2_client() {
|
|
1543
1708
|
rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"), LONG2NUM(0));
|
1544
1709
|
#endif
|
1545
1710
|
|
1711
|
+
#ifdef HAVE_CONST_MYSQL_OPTION_MULTI_STATEMENTS_ON
|
1712
|
+
rb_const_set(cMysql2Client, rb_intern("OPTION_MULTI_STATEMENTS_ON"),
|
1713
|
+
LONG2NUM(MYSQL_OPTION_MULTI_STATEMENTS_ON));
|
1714
|
+
#endif
|
1715
|
+
|
1716
|
+
#ifdef HAVE_CONST_MYSQL_OPTION_MULTI_STATEMENTS_OFF
|
1717
|
+
rb_const_set(cMysql2Client, rb_intern("OPTION_MULTI_STATEMENTS_OFF"),
|
1718
|
+
LONG2NUM(MYSQL_OPTION_MULTI_STATEMENTS_OFF));
|
1719
|
+
#endif
|
1720
|
+
|
1546
1721
|
#ifdef CLIENT_MULTI_STATEMENTS
|
1547
1722
|
rb_const_set(cMysql2Client, rb_intern("MULTI_STATEMENTS"),
|
1548
1723
|
LONG2NUM(CLIENT_MULTI_STATEMENTS));
|
@@ -1573,16 +1748,42 @@ void init_mysql2_client() {
|
|
1573
1748
|
LONG2NUM(CLIENT_BASIC_FLAGS));
|
1574
1749
|
#endif
|
1575
1750
|
|
1576
|
-
#
|
1751
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
1752
|
+
rb_const_set(cMysql2Client, rb_intern("CONNECT_ATTRS"),
|
1753
|
+
LONG2NUM(CLIENT_CONNECT_ATTRS));
|
1754
|
+
#else
|
1755
|
+
/* HACK because MySQL 5.5 and earlier don't define this constant,
|
1756
|
+
* but we're using it in our default connection flags. */
|
1757
|
+
rb_const_set(cMysql2Client, rb_intern("CONNECT_ATTRS"),
|
1758
|
+
INT2NUM(0));
|
1759
|
+
#endif
|
1760
|
+
|
1761
|
+
#ifdef CLIENT_SESSION_TRACK
|
1762
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK"), INT2NUM(CLIENT_SESSION_TRACK));
|
1763
|
+
/* From mysql_com.h -- but stable from at least 5.7.4 through 8.0.20 */
|
1764
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_SYSTEM_VARIABLES"), INT2NUM(SESSION_TRACK_SYSTEM_VARIABLES));
|
1765
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_SCHEMA"), INT2NUM(SESSION_TRACK_SCHEMA));
|
1766
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_STATE_CHANGE"), INT2NUM(SESSION_TRACK_STATE_CHANGE));
|
1767
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_GTIDS"), INT2NUM(SESSION_TRACK_GTIDS));
|
1768
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_TRANSACTION_CHARACTERISTICS"), INT2NUM(SESSION_TRACK_TRANSACTION_CHARACTERISTICS));
|
1769
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_TRANSACTION_STATE"), INT2NUM(SESSION_TRACK_TRANSACTION_STATE));
|
1770
|
+
#endif
|
1771
|
+
|
1772
|
+
#if defined(FULL_SSL_MODE_SUPPORT) // MySQL 5.6.36 and MySQL 5.7.11 and above
|
1577
1773
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
|
1578
1774
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_PREFERRED"), INT2NUM(SSL_MODE_PREFERRED));
|
1579
1775
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(SSL_MODE_REQUIRED));
|
1580
1776
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_CA"), INT2NUM(SSL_MODE_VERIFY_CA));
|
1581
1777
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(SSL_MODE_VERIFY_IDENTITY));
|
1582
|
-
#
|
1778
|
+
#else
|
1779
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT // MySQL 5.7.3 - 5.7.10 & MariaDB 10.x and later
|
1780
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(SSL_MODE_VERIFY_IDENTITY));
|
1781
|
+
#endif
|
1782
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE // MySQL 5.7.3 - 5.7.10 & MariaDB 10.x and later
|
1583
1783
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
|
1584
1784
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(SSL_MODE_REQUIRED));
|
1585
1785
|
#endif
|
1786
|
+
#endif
|
1586
1787
|
|
1587
1788
|
#ifndef HAVE_CONST_SSL_MODE_DISABLED
|
1588
1789
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(0));
|
@@ -1600,3 +1801,29 @@ void init_mysql2_client() {
|
|
1600
1801
|
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(0));
|
1601
1802
|
#endif
|
1602
1803
|
}
|
1804
|
+
|
1805
|
+
#define flag_to_bool(f) ((client->server_status & f) ? Qtrue : Qfalse)
|
1806
|
+
|
1807
|
+
void rb_mysql_set_server_query_flags(MYSQL *client, VALUE result) {
|
1808
|
+
VALUE server_flags = rb_hash_new();
|
1809
|
+
|
1810
|
+
#ifdef HAVE_CONST_SERVER_QUERY_NO_GOOD_INDEX_USED
|
1811
|
+
rb_hash_aset(server_flags, sym_no_good_index_used, flag_to_bool(SERVER_QUERY_NO_GOOD_INDEX_USED));
|
1812
|
+
#else
|
1813
|
+
rb_hash_aset(server_flags, sym_no_good_index_used, Qnil);
|
1814
|
+
#endif
|
1815
|
+
|
1816
|
+
#ifdef HAVE_CONST_SERVER_QUERY_NO_INDEX_USED
|
1817
|
+
rb_hash_aset(server_flags, sym_no_index_used, flag_to_bool(SERVER_QUERY_NO_INDEX_USED));
|
1818
|
+
#else
|
1819
|
+
rb_hash_aset(server_flags, sym_no_index_used, Qnil);
|
1820
|
+
#endif
|
1821
|
+
|
1822
|
+
#ifdef HAVE_CONST_SERVER_QUERY_WAS_SLOW
|
1823
|
+
rb_hash_aset(server_flags, sym_query_was_slow, flag_to_bool(SERVER_QUERY_WAS_SLOW));
|
1824
|
+
#else
|
1825
|
+
rb_hash_aset(server_flags, sym_query_was_slow, Qnil);
|
1826
|
+
#endif
|
1827
|
+
|
1828
|
+
rb_iv_set(result, "@server_flags", server_flags);
|
1829
|
+
}
|