mysql2 0.4.2 → 0.5.5
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 +231 -86
- data/ext/mysql2/client.c +527 -128
- data/ext/mysql2/client.h +11 -52
- data/ext/mysql2/extconf.rb +100 -21
- data/ext/mysql2/mysql2_ext.c +8 -2
- data/ext/mysql2/mysql2_ext.h +21 -8
- data/ext/mysql2/mysql_enc_name_to_ruby.h +60 -56
- data/ext/mysql2/mysql_enc_to_ruby.h +64 -3
- data/ext/mysql2/result.c +333 -109
- data/ext/mysql2/result.h +1 -0
- data/ext/mysql2/statement.c +247 -90
- data/ext/mysql2/statement.h +0 -2
- data/ext/mysql2/wait_for_single_fd.h +2 -1
- data/lib/mysql2/client.rb +71 -31
- 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 +432 -0
- data/support/C74CD1D8.asc +104 -0
- data/support/mysql_enc_to_ruby.rb +8 -3
- data/support/ruby_enc_to_mysql.rb +7 -5
- metadata +19 -61
- data/examples/eventmachine.rb +0 -21
- data/examples/threaded.rb +0 -18
- data/spec/configuration.yml.example +0 -17
- data/spec/em/em_spec.rb +0 -135
- data/spec/my.cnf.example +0 -9
- data/spec/mysql2/client_spec.rb +0 -939
- data/spec/mysql2/error_spec.rb +0 -84
- data/spec/mysql2/result_spec.rb +0 -510
- data/spec/mysql2/statement_spec.rb +0 -684
- data/spec/rcov.opts +0 -3
- data/spec/spec_helper.rb +0 -94
- 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,38 +15,73 @@
|
|
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) { \
|
30
26
|
rb_raise(cMysql2Error, "MySQL client is not initialized"); \
|
31
27
|
}
|
32
28
|
|
29
|
+
#if defined(HAVE_MYSQL_NET_VIO) || defined(HAVE_ST_NET_VIO)
|
30
|
+
#define CONNECTED(wrapper) (wrapper->client->net.vio != NULL && wrapper->client->net.fd != -1)
|
31
|
+
#elif defined(HAVE_MYSQL_NET_PVIO) || defined(HAVE_ST_NET_PVIO)
|
32
|
+
#define CONNECTED(wrapper) (wrapper->client->net.pvio != NULL && wrapper->client->net.fd != -1)
|
33
|
+
#endif
|
34
|
+
|
35
|
+
#define REQUIRE_CONNECTED(wrapper) \
|
36
|
+
REQUIRE_INITIALIZED(wrapper) \
|
37
|
+
if (!CONNECTED(wrapper) && !wrapper->reconnect_enabled) { \
|
38
|
+
rb_raise(cMysql2Error, "MySQL client is not connected"); \
|
39
|
+
}
|
40
|
+
|
33
41
|
#define REQUIRE_NOT_CONNECTED(wrapper) \
|
34
42
|
REQUIRE_INITIALIZED(wrapper) \
|
35
|
-
if (wrapper
|
43
|
+
if (CONNECTED(wrapper)) { \
|
36
44
|
rb_raise(cMysql2Error, "MySQL connection is already open"); \
|
37
45
|
}
|
38
46
|
|
39
47
|
/*
|
40
|
-
*
|
48
|
+
* compatibility with mysql-connector-c, where LIBMYSQL_VERSION is the correct
|
41
49
|
* variable to use, but MYSQL_SERVER_VERSION gives the correct numbers when
|
42
50
|
* linking against the server itself
|
43
51
|
*/
|
44
|
-
#
|
52
|
+
#if defined(MARIADB_CLIENT_VERSION_STR)
|
53
|
+
#define MYSQL_LINK_VERSION MARIADB_CLIENT_VERSION_STR
|
54
|
+
#elif defined(LIBMYSQL_VERSION)
|
45
55
|
#define MYSQL_LINK_VERSION LIBMYSQL_VERSION
|
46
56
|
#else
|
47
57
|
#define MYSQL_LINK_VERSION MYSQL_SERVER_VERSION
|
48
58
|
#endif
|
49
59
|
|
60
|
+
/*
|
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.
|
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
|
78
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
|
79
|
+
#define SSL_MODE_DISABLED 1
|
80
|
+
#define SSL_MODE_REQUIRED 3
|
81
|
+
#define HAVE_CONST_SSL_MODE_DISABLED
|
82
|
+
#define HAVE_CONST_SSL_MODE_REQUIRED
|
83
|
+
#endif
|
84
|
+
|
50
85
|
/*
|
51
86
|
* used to pass all arguments to mysql_real_connect while inside
|
52
87
|
* rb_thread_call_without_gvl
|
@@ -83,6 +118,82 @@ struct nogvl_select_db_args {
|
|
83
118
|
char *db;
|
84
119
|
};
|
85
120
|
|
121
|
+
static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
|
122
|
+
unsigned long version = mysql_get_client_version();
|
123
|
+
const char *version_str = mysql_get_client_info();
|
124
|
+
|
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);
|
133
|
+
return Qnil;
|
134
|
+
}
|
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)
|
142
|
+
GET_CLIENT(self);
|
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
|
160
|
+
if (val == SSL_MODE_DISABLED || val == SSL_MODE_REQUIRED) {
|
161
|
+
my_bool b = (val == SSL_MODE_REQUIRED);
|
162
|
+
int result = mysql_options(wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b);
|
163
|
+
return INT2NUM(result);
|
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;
|
171
|
+
}
|
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
|
+
*/
|
178
|
+
#ifdef FULL_SSL_MODE_SUPPORT
|
179
|
+
GET_CLIENT(self);
|
180
|
+
int val = NUM2INT(setting);
|
181
|
+
|
182
|
+
if (val != SSL_MODE_DISABLED && val != SSL_MODE_PREFERRED && val != SSL_MODE_REQUIRED && val != SSL_MODE_VERIFY_CA && val != SSL_MODE_VERIFY_IDENTITY) {
|
183
|
+
rb_raise(cMysql2Error, "ssl_mode= takes DISABLED, PREFERRED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY, you passed: %d", val );
|
184
|
+
}
|
185
|
+
int result = mysql_options(wrapper->client, MYSQL_OPT_SSL_MODE, &val);
|
186
|
+
|
187
|
+
return INT2NUM(result);
|
188
|
+
#endif
|
189
|
+
|
190
|
+
// Warn if we get this far
|
191
|
+
#ifdef NO_SSL_MODE_SUPPORT
|
192
|
+
rb_warn("Your mysql client library does not support setting ssl_mode");
|
193
|
+
return Qnil;
|
194
|
+
#endif
|
195
|
+
}
|
196
|
+
|
86
197
|
/*
|
87
198
|
* non-blocking mysql_*() functions that we won't be wrapping since
|
88
199
|
* they do not appear to hit the network nor issue any interruptible
|
@@ -108,20 +219,54 @@ struct nogvl_select_db_args {
|
|
108
219
|
static void rb_mysql_client_mark(void * wrapper) {
|
109
220
|
mysql_client_wrapper * w = wrapper;
|
110
221
|
if (w) {
|
111
|
-
|
112
|
-
|
222
|
+
rb_gc_mark_movable(w->encoding);
|
223
|
+
rb_gc_mark_movable(w->active_fiber);
|
113
224
|
}
|
114
225
|
}
|
115
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);
|
243
|
+
}
|
244
|
+
}
|
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
|
+
|
116
263
|
static VALUE rb_raise_mysql2_error(mysql_client_wrapper *wrapper) {
|
117
264
|
VALUE rb_error_msg = rb_str_new2(mysql_error(wrapper->client));
|
118
|
-
VALUE rb_sql_state =
|
265
|
+
VALUE rb_sql_state = rb_str_new2(mysql_sqlstate(wrapper->client));
|
119
266
|
VALUE e;
|
120
267
|
|
121
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
122
268
|
rb_enc_associate(rb_error_msg, rb_utf8_encoding());
|
123
269
|
rb_enc_associate(rb_sql_state, rb_usascii_encoding());
|
124
|
-
#endif
|
125
270
|
|
126
271
|
e = rb_funcall(cMysql2Error, intern_new_with_args, 4,
|
127
272
|
rb_error_msg,
|
@@ -211,30 +356,23 @@ static VALUE invalidate_fd(int clientfd)
|
|
211
356
|
static void *nogvl_close(void *ptr) {
|
212
357
|
mysql_client_wrapper *wrapper = ptr;
|
213
358
|
|
214
|
-
if (wrapper->
|
359
|
+
if (wrapper->initialized && !wrapper->closed) {
|
215
360
|
mysql_close(wrapper->client);
|
216
|
-
|
217
|
-
wrapper->
|
218
|
-
wrapper->
|
219
|
-
wrapper->active_thread = Qnil;
|
361
|
+
wrapper->closed = 1;
|
362
|
+
wrapper->reconnect_enabled = 0;
|
363
|
+
wrapper->active_fiber = Qnil;
|
220
364
|
}
|
221
365
|
|
222
366
|
return NULL;
|
223
367
|
}
|
224
368
|
|
225
|
-
/* this is called during GC */
|
226
|
-
static void rb_mysql_client_free(void *ptr) {
|
227
|
-
mysql_client_wrapper *wrapper = ptr;
|
228
|
-
decr_mysql2_client(wrapper);
|
229
|
-
}
|
230
|
-
|
231
369
|
void decr_mysql2_client(mysql_client_wrapper *wrapper)
|
232
370
|
{
|
233
371
|
wrapper->refcount--;
|
234
372
|
|
235
373
|
if (wrapper->refcount == 0) {
|
236
374
|
#ifndef _WIN32
|
237
|
-
if (wrapper->
|
375
|
+
if (CONNECTED(wrapper) && !wrapper->automatic_close) {
|
238
376
|
/* The client is being garbage collected while connected. Prevent
|
239
377
|
* mysql_close() from sending a mysql-QUIT or from calling shutdown() on
|
240
378
|
* the socket by invalidating it. invalidate_fd() will drop this
|
@@ -246,10 +384,12 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
|
|
246
384
|
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely\n");
|
247
385
|
close(wrapper->client->net.fd);
|
248
386
|
}
|
387
|
+
wrapper->client->net.fd = -1;
|
249
388
|
}
|
250
389
|
#endif
|
251
390
|
|
252
391
|
nogvl_close(wrapper);
|
392
|
+
xfree(wrapper->client);
|
253
393
|
xfree(wrapper);
|
254
394
|
}
|
255
395
|
}
|
@@ -257,14 +397,19 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
|
|
257
397
|
static VALUE allocate(VALUE klass) {
|
258
398
|
VALUE obj;
|
259
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
|
260
403
|
obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
|
404
|
+
#endif
|
261
405
|
wrapper->encoding = Qnil;
|
262
|
-
|
406
|
+
wrapper->active_fiber = Qnil;
|
407
|
+
wrapper->automatic_close = 1;
|
263
408
|
wrapper->server_version = 0;
|
264
409
|
wrapper->reconnect_enabled = 0;
|
265
410
|
wrapper->connect_timeout = 0;
|
266
|
-
wrapper->
|
267
|
-
wrapper->
|
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 */
|
268
413
|
wrapper->refcount = 1;
|
269
414
|
wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
|
270
415
|
|
@@ -295,9 +440,7 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
|
|
295
440
|
return str;
|
296
441
|
} else {
|
297
442
|
rb_str = rb_str_new((const char*)newStr, newLen);
|
298
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
299
443
|
rb_enc_copy(rb_str, str);
|
300
|
-
#endif
|
301
444
|
xfree(newStr);
|
302
445
|
return rb_str;
|
303
446
|
}
|
@@ -324,14 +467,43 @@ static VALUE rb_mysql_info(VALUE self) {
|
|
324
467
|
}
|
325
468
|
|
326
469
|
rb_str = rb_str_new2(info);
|
327
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
328
470
|
rb_enc_associate(rb_str, rb_utf8_encoding());
|
329
|
-
#endif
|
330
471
|
|
331
472
|
return rb_str;
|
332
473
|
}
|
333
474
|
|
334
|
-
static VALUE
|
475
|
+
static VALUE rb_mysql_get_ssl_cipher(VALUE self)
|
476
|
+
{
|
477
|
+
const char *cipher;
|
478
|
+
VALUE rb_str;
|
479
|
+
GET_CLIENT(self);
|
480
|
+
|
481
|
+
cipher = mysql_get_ssl_cipher(wrapper->client);
|
482
|
+
|
483
|
+
if (cipher == NULL) {
|
484
|
+
return Qnil;
|
485
|
+
}
|
486
|
+
|
487
|
+
rb_str = rb_str_new2(cipher);
|
488
|
+
rb_enc_associate(rb_str, rb_utf8_encoding());
|
489
|
+
|
490
|
+
return rb_str;
|
491
|
+
}
|
492
|
+
|
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) {
|
335
507
|
struct nogvl_connect_args args;
|
336
508
|
time_t start_time, end_time, elapsed_time, connect_timeout;
|
337
509
|
VALUE rv;
|
@@ -346,6 +518,11 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
346
518
|
args.mysql = wrapper->client;
|
347
519
|
args.client_flag = NUM2ULONG(flags);
|
348
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
|
+
|
349
526
|
if (wrapper->connect_timeout)
|
350
527
|
time(&start_time);
|
351
528
|
rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0);
|
@@ -372,33 +549,42 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
372
549
|
if (wrapper->connect_timeout)
|
373
550
|
mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &wrapper->connect_timeout);
|
374
551
|
if (rv == Qfalse)
|
375
|
-
|
552
|
+
rb_raise_mysql2_error(wrapper);
|
376
553
|
}
|
377
554
|
|
555
|
+
wrapper->closed = 0;
|
378
556
|
wrapper->server_version = mysql_get_server_version(wrapper->client);
|
379
|
-
wrapper->connected = 1;
|
380
557
|
return self;
|
381
558
|
}
|
382
559
|
|
383
560
|
/*
|
384
|
-
*
|
385
|
-
*
|
386
|
-
*
|
387
|
-
*
|
561
|
+
* Immediately disconnect from the server; normally the garbage collector
|
562
|
+
* will disconnect automatically when a connection is no longer needed.
|
563
|
+
* Explicitly closing this will free up server resources sooner than waiting
|
564
|
+
* for the garbage collector.
|
388
565
|
*
|
389
|
-
* @
|
390
|
-
* @return [void]
|
566
|
+
* @return [nil]
|
391
567
|
*/
|
392
568
|
static VALUE rb_mysql_client_close(VALUE self) {
|
393
569
|
GET_CLIENT(self);
|
394
570
|
|
395
|
-
if (wrapper->
|
571
|
+
if (wrapper->client) {
|
396
572
|
rb_thread_call_without_gvl(nogvl_close, wrapper, RUBY_UBF_IO, 0);
|
397
573
|
}
|
398
574
|
|
399
575
|
return Qnil;
|
400
576
|
}
|
401
577
|
|
578
|
+
/* call-seq:
|
579
|
+
* client.closed?
|
580
|
+
*
|
581
|
+
* @return [Boolean]
|
582
|
+
*/
|
583
|
+
static VALUE rb_mysql_client_closed(VALUE self) {
|
584
|
+
GET_CLIENT(self);
|
585
|
+
return CONNECTED(wrapper) ? Qfalse : Qtrue;
|
586
|
+
}
|
587
|
+
|
402
588
|
/*
|
403
589
|
* mysql_send_query is unlikely to block since most queries are small
|
404
590
|
* enough to fit in a socket buffer, but sometimes large UPDATE and
|
@@ -413,13 +599,13 @@ static void *nogvl_send_query(void *ptr) {
|
|
413
599
|
return (void*)(rv == 0 ? Qtrue : Qfalse);
|
414
600
|
}
|
415
601
|
|
416
|
-
static VALUE do_send_query(
|
417
|
-
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;
|
418
604
|
mysql_client_wrapper *wrapper = query_args->wrapper;
|
419
|
-
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) {
|
420
606
|
/* an error occurred, we're not active anymore */
|
421
|
-
|
422
|
-
|
607
|
+
wrapper->active_fiber = Qnil;
|
608
|
+
rb_raise_mysql2_error(wrapper);
|
423
609
|
}
|
424
610
|
return Qnil;
|
425
611
|
}
|
@@ -448,7 +634,7 @@ static void *nogvl_do_result(void *ptr, char use_result) {
|
|
448
634
|
|
449
635
|
/* once our result is stored off, this connection is
|
450
636
|
ready for another command to be issued */
|
451
|
-
|
637
|
+
wrapper->active_fiber = Qnil;
|
452
638
|
|
453
639
|
return result;
|
454
640
|
}
|
@@ -474,17 +660,17 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
|
|
474
660
|
GET_CLIENT(self);
|
475
661
|
|
476
662
|
/* if we're not waiting on a result, do nothing */
|
477
|
-
if (NIL_P(wrapper->
|
663
|
+
if (NIL_P(wrapper->active_fiber))
|
478
664
|
return Qnil;
|
479
665
|
|
480
666
|
REQUIRE_CONNECTED(wrapper);
|
481
667
|
if ((VALUE)rb_thread_call_without_gvl(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
|
482
668
|
/* an error occurred, mark this connection inactive */
|
483
|
-
|
484
|
-
|
669
|
+
wrapper->active_fiber = Qnil;
|
670
|
+
rb_raise_mysql2_error(wrapper);
|
485
671
|
}
|
486
672
|
|
487
|
-
is_streaming = rb_hash_aref(
|
673
|
+
is_streaming = rb_hash_aref(rb_ivar_get(self, intern_current_query_options), sym_stream);
|
488
674
|
if (is_streaming == Qtrue) {
|
489
675
|
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_use_result, wrapper, RUBY_UBF_IO, 0);
|
490
676
|
} else {
|
@@ -493,18 +679,21 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
|
|
493
679
|
|
494
680
|
if (result == NULL) {
|
495
681
|
if (mysql_errno(wrapper->client) != 0) {
|
496
|
-
|
682
|
+
wrapper->active_fiber = Qnil;
|
497
683
|
rb_raise_mysql2_error(wrapper);
|
498
684
|
}
|
499
685
|
/* no data and no error, so query was not a SELECT */
|
500
686
|
return Qnil;
|
501
687
|
}
|
502
688
|
|
503
|
-
|
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));
|
504
691
|
(void)RB_GC_GUARD(current);
|
505
692
|
Check_Type(current, T_HASH);
|
506
693
|
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
|
507
694
|
|
695
|
+
rb_mysql_set_server_query_flags(wrapper->client, resultObj);
|
696
|
+
|
508
697
|
return resultObj;
|
509
698
|
}
|
510
699
|
|
@@ -517,29 +706,31 @@ struct async_query_args {
|
|
517
706
|
static VALUE disconnect_and_raise(VALUE self, VALUE error) {
|
518
707
|
GET_CLIENT(self);
|
519
708
|
|
520
|
-
|
521
|
-
wrapper->connected = 0;
|
709
|
+
wrapper->active_fiber = Qnil;
|
522
710
|
|
523
711
|
/* Invalidate the MySQL socket to prevent further communication.
|
524
712
|
* The GC will come along later and call mysql_close to free it.
|
525
713
|
*/
|
526
|
-
if (
|
527
|
-
|
528
|
-
|
714
|
+
if (CONNECTED(wrapper)) {
|
715
|
+
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
|
716
|
+
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, closing unsafely\n");
|
717
|
+
close(wrapper->client->net.fd);
|
718
|
+
}
|
719
|
+
wrapper->client->net.fd = -1;
|
529
720
|
}
|
530
721
|
|
531
722
|
rb_exc_raise(error);
|
532
723
|
}
|
533
724
|
|
534
|
-
static VALUE do_query(
|
535
|
-
struct async_query_args *async_args = args;
|
725
|
+
static VALUE do_query(VALUE args) {
|
726
|
+
struct async_query_args *async_args = (void *)args;
|
536
727
|
struct timeval tv;
|
537
728
|
struct timeval *tvp;
|
538
729
|
long int sec;
|
539
730
|
int retval;
|
540
731
|
VALUE read_timeout;
|
541
732
|
|
542
|
-
read_timeout =
|
733
|
+
read_timeout = rb_ivar_get(async_args->self, intern_read_timeout);
|
543
734
|
|
544
735
|
tvp = NULL;
|
545
736
|
if (!NIL_P(read_timeout)) {
|
@@ -560,7 +751,7 @@ static VALUE do_query(void *args) {
|
|
560
751
|
retval = rb_wait_for_single_fd(async_args->fd, RB_WAITFD_IN, tvp);
|
561
752
|
|
562
753
|
if (retval == 0) {
|
563
|
-
rb_raise(
|
754
|
+
rb_raise(cMysql2TimeoutError, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
|
564
755
|
}
|
565
756
|
|
566
757
|
if (retval < 0) {
|
@@ -574,39 +765,45 @@ static VALUE do_query(void *args) {
|
|
574
765
|
|
575
766
|
return Qnil;
|
576
767
|
}
|
577
|
-
#
|
578
|
-
static VALUE finish_and_mark_inactive(void *args) {
|
579
|
-
VALUE self = args;
|
580
|
-
MYSQL_RES *result;
|
768
|
+
#endif
|
581
769
|
|
770
|
+
static VALUE disconnect_and_mark_inactive(VALUE self) {
|
582
771
|
GET_CLIENT(self);
|
583
772
|
|
584
|
-
if
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
773
|
+
/* Check if execution terminated while result was still being read. */
|
774
|
+
if (!NIL_P(wrapper->active_fiber)) {
|
775
|
+
if (CONNECTED(wrapper)) {
|
776
|
+
/* Invalidate the MySQL socket to prevent further communication. */
|
777
|
+
#ifndef _WIN32
|
778
|
+
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
|
779
|
+
rb_warn("mysql2 failed to invalidate FD safely, closing unsafely\n");
|
780
|
+
close(wrapper->client->net.fd);
|
781
|
+
}
|
782
|
+
#else
|
783
|
+
close(wrapper->client->net.fd);
|
784
|
+
#endif
|
785
|
+
wrapper->client->net.fd = -1;
|
786
|
+
}
|
787
|
+
/* Skip mysql client check performed before command execution. */
|
788
|
+
wrapper->client->status = MYSQL_STATUS_READY;
|
789
|
+
wrapper->active_fiber = Qnil;
|
592
790
|
}
|
593
791
|
|
594
792
|
return Qnil;
|
595
793
|
}
|
596
|
-
#endif
|
597
794
|
|
598
|
-
void
|
599
|
-
VALUE
|
795
|
+
static void rb_mysql_client_set_active_fiber(VALUE self) {
|
796
|
+
VALUE fiber_current = rb_fiber_current();
|
600
797
|
GET_CLIENT(self);
|
601
798
|
|
602
799
|
// see if this connection is still waiting on a result from a previous query
|
603
|
-
if (NIL_P(wrapper->
|
800
|
+
if (NIL_P(wrapper->active_fiber)) {
|
604
801
|
// mark this connection active
|
605
|
-
wrapper->
|
606
|
-
} else if (wrapper->
|
802
|
+
wrapper->active_fiber = fiber_current;
|
803
|
+
} else if (wrapper->active_fiber == fiber_current) {
|
607
804
|
rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
|
608
805
|
} else {
|
609
|
-
VALUE inspect = rb_inspect(wrapper->
|
806
|
+
VALUE inspect = rb_inspect(wrapper->active_fiber);
|
610
807
|
const char *thr = StringValueCStr(inspect);
|
611
808
|
|
612
809
|
rb_raise(cMysql2Error, "This connection is in use by: %s", thr);
|
@@ -649,7 +846,7 @@ static VALUE rb_mysql_client_abandon_results(VALUE self) {
|
|
649
846
|
* Query the database with +sql+, with optional +options+. For the possible
|
650
847
|
* options, see default_query_options on the Mysql2::Client class.
|
651
848
|
*/
|
652
|
-
static VALUE
|
849
|
+
static VALUE rb_mysql_query(VALUE self, VALUE sql, VALUE current) {
|
653
850
|
#ifndef _WIN32
|
654
851
|
struct async_query_args async_args;
|
655
852
|
#endif
|
@@ -661,23 +858,20 @@ static VALUE rb_query(VALUE self, VALUE sql, VALUE current) {
|
|
661
858
|
|
662
859
|
(void)RB_GC_GUARD(current);
|
663
860
|
Check_Type(current, T_HASH);
|
664
|
-
|
861
|
+
rb_ivar_set(self, intern_current_query_options, current);
|
665
862
|
|
666
863
|
Check_Type(sql, T_STRING);
|
667
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
668
864
|
/* ensure the string is in the encoding the connection is expecting */
|
669
865
|
args.sql = rb_str_export_to_enc(sql, rb_to_encoding(wrapper->encoding));
|
670
|
-
#else
|
671
|
-
args.sql = sql;
|
672
|
-
#endif
|
673
866
|
args.sql_ptr = RSTRING_PTR(args.sql);
|
674
867
|
args.sql_len = RSTRING_LEN(args.sql);
|
675
868
|
args.wrapper = wrapper;
|
676
869
|
|
677
|
-
|
870
|
+
rb_mysql_client_set_active_fiber(self);
|
678
871
|
|
679
872
|
#ifndef _WIN32
|
680
873
|
rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);
|
874
|
+
(void)RB_GC_GUARD(sql);
|
681
875
|
|
682
876
|
if (rb_hash_aref(current, sym_async) == Qtrue) {
|
683
877
|
return Qnil;
|
@@ -687,13 +881,14 @@ static VALUE rb_query(VALUE self, VALUE sql, VALUE current) {
|
|
687
881
|
|
688
882
|
rb_rescue2(do_query, (VALUE)&async_args, disconnect_and_raise, self, rb_eException, (VALUE)0);
|
689
883
|
|
690
|
-
return rb_mysql_client_async_result
|
884
|
+
return rb_ensure(rb_mysql_client_async_result, self, disconnect_and_mark_inactive, self);
|
691
885
|
}
|
692
886
|
#else
|
693
|
-
do_send_query(&args);
|
887
|
+
do_send_query((VALUE)&args);
|
888
|
+
(void)RB_GC_GUARD(sql);
|
694
889
|
|
695
890
|
/* this will just block until the result is ready */
|
696
|
-
return rb_ensure(rb_mysql_client_async_result, self,
|
891
|
+
return rb_ensure(rb_mysql_client_async_result, self, disconnect_and_mark_inactive, self);
|
697
892
|
#endif
|
698
893
|
}
|
699
894
|
|
@@ -706,20 +901,16 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
706
901
|
unsigned char *newStr;
|
707
902
|
VALUE rb_str;
|
708
903
|
unsigned long newLen, oldLen;
|
709
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
710
904
|
rb_encoding *default_internal_enc;
|
711
905
|
rb_encoding *conn_enc;
|
712
|
-
#endif
|
713
906
|
GET_CLIENT(self);
|
714
907
|
|
715
908
|
REQUIRE_CONNECTED(wrapper);
|
716
909
|
Check_Type(str, T_STRING);
|
717
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
718
910
|
default_internal_enc = rb_default_internal_encoding();
|
719
911
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
720
912
|
/* ensure the string is in the encoding the connection is expecting */
|
721
913
|
str = rb_str_export_to_enc(str, conn_enc);
|
722
|
-
#endif
|
723
914
|
|
724
915
|
oldLen = RSTRING_LEN(str);
|
725
916
|
newStr = xmalloc(oldLen*2+1);
|
@@ -727,21 +918,17 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
727
918
|
newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, RSTRING_PTR(str), oldLen);
|
728
919
|
if (newLen == oldLen) {
|
729
920
|
/* no need to return a new ruby string if nothing changed */
|
730
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
731
921
|
if (default_internal_enc) {
|
732
922
|
str = rb_str_export_to_enc(str, default_internal_enc);
|
733
923
|
}
|
734
|
-
#endif
|
735
924
|
xfree(newStr);
|
736
925
|
return str;
|
737
926
|
} else {
|
738
927
|
rb_str = rb_str_new((const char*)newStr, newLen);
|
739
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
740
928
|
rb_enc_associate(rb_str, conn_enc);
|
741
929
|
if (default_internal_enc) {
|
742
930
|
rb_str = rb_str_export_to_enc(rb_str, default_internal_enc);
|
743
931
|
}
|
744
|
-
#endif
|
745
932
|
xfree(newStr);
|
746
933
|
return rb_str;
|
747
934
|
}
|
@@ -787,10 +974,12 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
|
787
974
|
retval = &boolval;
|
788
975
|
break;
|
789
976
|
|
977
|
+
#ifdef MYSQL_SECURE_AUTH
|
790
978
|
case MYSQL_SECURE_AUTH:
|
791
979
|
boolval = (value == Qfalse ? 0 : 1);
|
792
980
|
retval = &boolval;
|
793
981
|
break;
|
982
|
+
#endif
|
794
983
|
|
795
984
|
case MYSQL_READ_DEFAULT_FILE:
|
796
985
|
charval = (const char *)StringValueCStr(value);
|
@@ -807,6 +996,20 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
|
807
996
|
retval = charval;
|
808
997
|
break;
|
809
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
|
+
|
1006
|
+
#ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
|
1007
|
+
case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
|
1008
|
+
boolval = (value == Qfalse ? 0 : 1);
|
1009
|
+
retval = &boolval;
|
1010
|
+
break;
|
1011
|
+
#endif
|
1012
|
+
|
810
1013
|
default:
|
811
1014
|
return Qfalse;
|
812
1015
|
}
|
@@ -843,10 +1046,8 @@ static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE klass) {
|
|
843
1046
|
version = rb_str_new2(mysql_get_client_info());
|
844
1047
|
header_version = rb_str_new2(MYSQL_LINK_VERSION);
|
845
1048
|
|
846
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
847
1049
|
rb_enc_associate(version, rb_usascii_encoding());
|
848
1050
|
rb_enc_associate(header_version, rb_usascii_encoding());
|
849
|
-
#endif
|
850
1051
|
|
851
1052
|
rb_hash_aset(version_info, sym_id, LONG2NUM(mysql_get_client_version()));
|
852
1053
|
rb_hash_aset(version_info, sym_version, version);
|
@@ -862,27 +1063,21 @@ static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE klass) {
|
|
862
1063
|
*/
|
863
1064
|
static VALUE rb_mysql_client_server_info(VALUE self) {
|
864
1065
|
VALUE version, server_info;
|
865
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
866
1066
|
rb_encoding *default_internal_enc;
|
867
1067
|
rb_encoding *conn_enc;
|
868
|
-
#endif
|
869
1068
|
GET_CLIENT(self);
|
870
1069
|
|
871
1070
|
REQUIRE_CONNECTED(wrapper);
|
872
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
873
1071
|
default_internal_enc = rb_default_internal_encoding();
|
874
1072
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
875
|
-
#endif
|
876
1073
|
|
877
1074
|
version = rb_hash_new();
|
878
1075
|
rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
|
879
1076
|
server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
|
880
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
881
1077
|
rb_enc_associate(server_info, conn_enc);
|
882
1078
|
if (default_internal_enc) {
|
883
1079
|
server_info = rb_str_export_to_enc(server_info, default_internal_enc);
|
884
1080
|
}
|
885
|
-
#endif
|
886
1081
|
rb_hash_aset(version, sym_version, server_info);
|
887
1082
|
return version;
|
888
1083
|
}
|
@@ -916,6 +1111,36 @@ static VALUE rb_mysql_client_last_id(VALUE self) {
|
|
916
1111
|
return ULL2NUM(mysql_insert_id(wrapper->client));
|
917
1112
|
}
|
918
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
|
+
|
919
1144
|
/* call-seq:
|
920
1145
|
* client.affected_rows
|
921
1146
|
*
|
@@ -996,13 +1221,30 @@ static void *nogvl_ping(void *ptr) {
|
|
996
1221
|
static VALUE rb_mysql_client_ping(VALUE self) {
|
997
1222
|
GET_CLIENT(self);
|
998
1223
|
|
999
|
-
if (!wrapper
|
1224
|
+
if (!CONNECTED(wrapper)) {
|
1000
1225
|
return Qfalse;
|
1001
1226
|
} else {
|
1002
1227
|
return (VALUE)rb_thread_call_without_gvl(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
|
1003
1228
|
}
|
1004
1229
|
}
|
1005
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
|
+
|
1006
1248
|
/* call-seq:
|
1007
1249
|
* client.more_results?
|
1008
1250
|
*
|
@@ -1011,10 +1253,10 @@ static VALUE rb_mysql_client_ping(VALUE self) {
|
|
1011
1253
|
static VALUE rb_mysql_client_more_results(VALUE self)
|
1012
1254
|
{
|
1013
1255
|
GET_CLIENT(self);
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1256
|
+
if (mysql_more_results(wrapper->client) == 0)
|
1257
|
+
return Qfalse;
|
1258
|
+
else
|
1259
|
+
return Qtrue;
|
1018
1260
|
}
|
1019
1261
|
|
1020
1262
|
/* call-seq:
|
@@ -1061,7 +1303,8 @@ static VALUE rb_mysql_client_store_result(VALUE self)
|
|
1061
1303
|
return Qnil;
|
1062
1304
|
}
|
1063
1305
|
|
1064
|
-
|
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));
|
1065
1308
|
(void)RB_GC_GUARD(current);
|
1066
1309
|
Check_Type(current, T_HASH);
|
1067
1310
|
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
|
@@ -1069,7 +1312,6 @@ static VALUE rb_mysql_client_store_result(VALUE self)
|
|
1069
1312
|
return resultObj;
|
1070
1313
|
}
|
1071
1314
|
|
1072
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1073
1315
|
/* call-seq:
|
1074
1316
|
* client.encoding
|
1075
1317
|
*
|
@@ -1079,7 +1321,39 @@ static VALUE rb_mysql_client_encoding(VALUE self) {
|
|
1079
1321
|
GET_CLIENT(self);
|
1080
1322
|
return wrapper->encoding;
|
1081
1323
|
}
|
1324
|
+
|
1325
|
+
/* call-seq:
|
1326
|
+
* client.automatic_close?
|
1327
|
+
*
|
1328
|
+
* @return [Boolean]
|
1329
|
+
*/
|
1330
|
+
static VALUE get_automatic_close(VALUE self) {
|
1331
|
+
GET_CLIENT(self);
|
1332
|
+
return wrapper->automatic_close ? Qtrue : Qfalse;
|
1333
|
+
}
|
1334
|
+
|
1335
|
+
/* call-seq:
|
1336
|
+
* client.automatic_close = false
|
1337
|
+
*
|
1338
|
+
* Set this to +false+ to leave the connection open after it is garbage
|
1339
|
+
* collected. To avoid "Aborted connection" errors on the server, explicitly
|
1340
|
+
* call +close+ when the connection is no longer needed.
|
1341
|
+
*
|
1342
|
+
* @see http://dev.mysql.com/doc/en/communication-errors.html
|
1343
|
+
*/
|
1344
|
+
static VALUE set_automatic_close(VALUE self, VALUE value) {
|
1345
|
+
GET_CLIENT(self);
|
1346
|
+
if (RTEST(value)) {
|
1347
|
+
wrapper->automatic_close = 1;
|
1348
|
+
} else {
|
1349
|
+
#ifndef _WIN32
|
1350
|
+
wrapper->automatic_close = 0;
|
1351
|
+
#else
|
1352
|
+
rb_warn("Connections are always closed by garbage collector on Windows");
|
1082
1353
|
#endif
|
1354
|
+
}
|
1355
|
+
return value;
|
1356
|
+
}
|
1083
1357
|
|
1084
1358
|
/* call-seq:
|
1085
1359
|
* client.reconnect = true
|
@@ -1116,7 +1390,7 @@ static VALUE set_read_timeout(VALUE self, VALUE value) {
|
|
1116
1390
|
/* Set the instance variable here even though _mysql_client_options
|
1117
1391
|
might not succeed, because the timeout is used in other ways
|
1118
1392
|
elsewhere */
|
1119
|
-
|
1393
|
+
rb_ivar_set(self, intern_read_timeout, value);
|
1120
1394
|
return _mysql_client_options(self, MYSQL_OPT_READ_TIMEOUT, value);
|
1121
1395
|
}
|
1122
1396
|
|
@@ -1132,16 +1406,14 @@ static VALUE set_write_timeout(VALUE self, VALUE value) {
|
|
1132
1406
|
|
1133
1407
|
static VALUE set_charset_name(VALUE self, VALUE value) {
|
1134
1408
|
char *charset_name;
|
1135
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1136
1409
|
const struct mysql2_mysql_enc_name_to_rb_map *mysql2rb;
|
1137
1410
|
rb_encoding *enc;
|
1138
1411
|
VALUE rb_enc;
|
1139
|
-
#endif
|
1140
1412
|
GET_CLIENT(self);
|
1141
1413
|
|
1414
|
+
Check_Type(value, T_STRING);
|
1142
1415
|
charset_name = RSTRING_PTR(value);
|
1143
1416
|
|
1144
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1145
1417
|
mysql2rb = mysql2_mysql_enc_name_to_rb(charset_name, (unsigned int)RSTRING_LEN(value));
|
1146
1418
|
if (mysql2rb == NULL || mysql2rb->rb_name == NULL) {
|
1147
1419
|
VALUE inspect = rb_inspect(value);
|
@@ -1151,7 +1423,6 @@ static VALUE set_charset_name(VALUE self, VALUE value) {
|
|
1151
1423
|
rb_enc = rb_enc_from_encoding(enc);
|
1152
1424
|
wrapper->encoding = rb_enc;
|
1153
1425
|
}
|
1154
|
-
#endif
|
1155
1426
|
|
1156
1427
|
if (mysql_options(wrapper->client, MYSQL_SET_CHARSET_NAME, charset_name)) {
|
1157
1428
|
/* TODO: warning - unable to set charset */
|
@@ -1175,7 +1446,12 @@ static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE
|
|
1175
1446
|
}
|
1176
1447
|
|
1177
1448
|
static VALUE set_secure_auth(VALUE self, VALUE value) {
|
1449
|
+
/* This option was deprecated in MySQL 5.x and removed in MySQL 8.0 */
|
1450
|
+
#ifdef MYSQL_SECURE_AUTH
|
1178
1451
|
return _mysql_client_options(self, MYSQL_SECURE_AUTH, value);
|
1452
|
+
#else
|
1453
|
+
return Qfalse;
|
1454
|
+
#endif
|
1179
1455
|
}
|
1180
1456
|
|
1181
1457
|
static VALUE set_read_default_file(VALUE self, VALUE value) {
|
@@ -1190,12 +1466,28 @@ static VALUE set_init_command(VALUE self, VALUE value) {
|
|
1190
1466
|
return _mysql_client_options(self, MYSQL_INIT_COMMAND, value);
|
1191
1467
|
}
|
1192
1468
|
|
1469
|
+
static VALUE set_default_auth(VALUE self, VALUE value) {
|
1470
|
+
#ifdef HAVE_MYSQL_DEFAULT_AUTH
|
1471
|
+
return _mysql_client_options(self, MYSQL_DEFAULT_AUTH, value);
|
1472
|
+
#else
|
1473
|
+
rb_raise(cMysql2Error, "pluggable authentication is not available, you may need a newer MySQL client library");
|
1474
|
+
#endif
|
1475
|
+
}
|
1476
|
+
|
1477
|
+
static VALUE set_enable_cleartext_plugin(VALUE self, VALUE value) {
|
1478
|
+
#ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
|
1479
|
+
return _mysql_client_options(self, MYSQL_ENABLE_CLEARTEXT_PLUGIN, value);
|
1480
|
+
#else
|
1481
|
+
rb_raise(cMysql2Error, "enable-cleartext-plugin is not available, you may need a newer MySQL client library");
|
1482
|
+
#endif
|
1483
|
+
}
|
1484
|
+
|
1193
1485
|
static VALUE initialize_ext(VALUE self) {
|
1194
1486
|
GET_CLIENT(self);
|
1195
1487
|
|
1196
1488
|
if ((VALUE)rb_thread_call_without_gvl(nogvl_init, wrapper, RUBY_UBF_IO, 0) == Qfalse) {
|
1197
1489
|
/* TODO: warning - not enough memory? */
|
1198
|
-
|
1490
|
+
rb_raise_mysql2_error(wrapper);
|
1199
1491
|
}
|
1200
1492
|
|
1201
1493
|
wrapper->initialized = 1;
|
@@ -1243,6 +1535,7 @@ void init_mysql2_client() {
|
|
1243
1535
|
mMysql2 = rb_define_module("Mysql2"); Teach RDoc about Mysql2 constant.
|
1244
1536
|
#endif
|
1245
1537
|
cMysql2Client = rb_define_class_under(mMysql2, "Client", rb_cObject);
|
1538
|
+
rb_global_variable(&cMysql2Client);
|
1246
1539
|
|
1247
1540
|
rb_define_alloc_func(cMysql2Client, allocate);
|
1248
1541
|
|
@@ -1250,6 +1543,7 @@ void init_mysql2_client() {
|
|
1250
1543
|
rb_define_singleton_method(cMysql2Client, "info", rb_mysql_client_info, 0);
|
1251
1544
|
|
1252
1545
|
rb_define_method(cMysql2Client, "close", rb_mysql_client_close, 0);
|
1546
|
+
rb_define_method(cMysql2Client, "closed?", rb_mysql_client_closed, 0);
|
1253
1547
|
rb_define_method(cMysql2Client, "abandon_results!", rb_mysql_client_abandon_results, 0);
|
1254
1548
|
rb_define_method(cMysql2Client, "escape", rb_mysql_client_real_escape, 1);
|
1255
1549
|
rb_define_method(cMysql2Client, "server_info", rb_mysql_client_server_info, 0);
|
@@ -1261,15 +1555,18 @@ void init_mysql2_client() {
|
|
1261
1555
|
rb_define_method(cMysql2Client, "thread_id", rb_mysql_client_thread_id, 0);
|
1262
1556
|
rb_define_method(cMysql2Client, "ping", rb_mysql_client_ping, 0);
|
1263
1557
|
rb_define_method(cMysql2Client, "select_db", rb_mysql_client_select_db, 1);
|
1558
|
+
rb_define_method(cMysql2Client, "set_server_option", rb_mysql_client_set_server_option, 1);
|
1264
1559
|
rb_define_method(cMysql2Client, "more_results?", rb_mysql_client_more_results, 0);
|
1265
1560
|
rb_define_method(cMysql2Client, "next_result", rb_mysql_client_next_result, 0);
|
1266
1561
|
rb_define_method(cMysql2Client, "store_result", rb_mysql_client_store_result, 0);
|
1562
|
+
rb_define_method(cMysql2Client, "automatic_close?", get_automatic_close, 0);
|
1563
|
+
rb_define_method(cMysql2Client, "automatic_close=", set_automatic_close, 1);
|
1267
1564
|
rb_define_method(cMysql2Client, "reconnect=", set_reconnect, 1);
|
1268
1565
|
rb_define_method(cMysql2Client, "warning_count", rb_mysql_client_warning_count, 0);
|
1269
1566
|
rb_define_method(cMysql2Client, "query_info_string", rb_mysql_info, 0);
|
1270
|
-
|
1567
|
+
rb_define_method(cMysql2Client, "ssl_cipher", rb_mysql_get_ssl_cipher, 0);
|
1271
1568
|
rb_define_method(cMysql2Client, "encoding", rb_mysql_client_encoding, 0);
|
1272
|
-
|
1569
|
+
rb_define_method(cMysql2Client, "session_track", rb_mysql_client_session_track, 1);
|
1273
1570
|
|
1274
1571
|
rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
|
1275
1572
|
rb_define_private_method(cMysql2Client, "read_timeout=", set_read_timeout, 1);
|
@@ -1280,10 +1577,13 @@ void init_mysql2_client() {
|
|
1280
1577
|
rb_define_private_method(cMysql2Client, "default_file=", set_read_default_file, 1);
|
1281
1578
|
rb_define_private_method(cMysql2Client, "default_group=", set_read_default_group, 1);
|
1282
1579
|
rb_define_private_method(cMysql2Client, "init_command=", set_init_command, 1);
|
1580
|
+
rb_define_private_method(cMysql2Client, "default_auth=", set_default_auth, 1);
|
1283
1581
|
rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
|
1582
|
+
rb_define_private_method(cMysql2Client, "ssl_mode=", rb_set_ssl_mode_option, 1);
|
1583
|
+
rb_define_private_method(cMysql2Client, "enable_cleartext_plugin=", set_enable_cleartext_plugin, 1);
|
1284
1584
|
rb_define_private_method(cMysql2Client, "initialize_ext", initialize_ext, 0);
|
1285
|
-
rb_define_private_method(cMysql2Client, "connect",
|
1286
|
-
rb_define_private_method(cMysql2Client, "_query",
|
1585
|
+
rb_define_private_method(cMysql2Client, "connect", rb_mysql_connect, 8);
|
1586
|
+
rb_define_private_method(cMysql2Client, "_query", rb_mysql_query, 2);
|
1287
1587
|
|
1288
1588
|
sym_id = ID2SYM(rb_intern("id"));
|
1289
1589
|
sym_version = ID2SYM(rb_intern("version"));
|
@@ -1294,14 +1594,24 @@ void init_mysql2_client() {
|
|
1294
1594
|
sym_array = ID2SYM(rb_intern("array"));
|
1295
1595
|
sym_stream = ID2SYM(rb_intern("stream"));
|
1296
1596
|
|
1597
|
+
sym_no_good_index_used = ID2SYM(rb_intern("no_good_index_used"));
|
1598
|
+
sym_no_index_used = ID2SYM(rb_intern("no_index_used"));
|
1599
|
+
sym_query_was_slow = ID2SYM(rb_intern("query_was_slow"));
|
1600
|
+
|
1297
1601
|
intern_brackets = rb_intern("[]");
|
1298
1602
|
intern_merge = rb_intern("merge");
|
1299
1603
|
intern_merge_bang = rb_intern("merge!");
|
1300
1604
|
intern_new_with_args = rb_intern("new_with_args");
|
1605
|
+
intern_current_query_options = rb_intern("@current_query_options");
|
1606
|
+
intern_read_timeout = rb_intern("@read_timeout");
|
1301
1607
|
|
1302
1608
|
#ifdef CLIENT_LONG_PASSWORD
|
1303
1609
|
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
|
1304
1610
|
LONG2NUM(CLIENT_LONG_PASSWORD));
|
1611
|
+
#else
|
1612
|
+
/* HACK because MariaDB 10.2 no longer defines this constant,
|
1613
|
+
* but we're using it in our default connection flags. */
|
1614
|
+
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"), INT2NUM(0));
|
1305
1615
|
#endif
|
1306
1616
|
|
1307
1617
|
#ifdef CLIENT_FOUND_ROWS
|
@@ -1379,6 +1689,16 @@ void init_mysql2_client() {
|
|
1379
1689
|
rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"), LONG2NUM(0));
|
1380
1690
|
#endif
|
1381
1691
|
|
1692
|
+
#ifdef HAVE_CONST_MYSQL_OPTION_MULTI_STATEMENTS_ON
|
1693
|
+
rb_const_set(cMysql2Client, rb_intern("OPTION_MULTI_STATEMENTS_ON"),
|
1694
|
+
LONG2NUM(MYSQL_OPTION_MULTI_STATEMENTS_ON));
|
1695
|
+
#endif
|
1696
|
+
|
1697
|
+
#ifdef HAVE_CONST_MYSQL_OPTION_MULTI_STATEMENTS_OFF
|
1698
|
+
rb_const_set(cMysql2Client, rb_intern("OPTION_MULTI_STATEMENTS_OFF"),
|
1699
|
+
LONG2NUM(MYSQL_OPTION_MULTI_STATEMENTS_OFF));
|
1700
|
+
#endif
|
1701
|
+
|
1382
1702
|
#ifdef CLIENT_MULTI_STATEMENTS
|
1383
1703
|
rb_const_set(cMysql2Client, rb_intern("MULTI_STATEMENTS"),
|
1384
1704
|
LONG2NUM(CLIENT_MULTI_STATEMENTS));
|
@@ -1408,4 +1728,83 @@ void init_mysql2_client() {
|
|
1408
1728
|
rb_const_set(cMysql2Client, rb_intern("BASIC_FLAGS"),
|
1409
1729
|
LONG2NUM(CLIENT_BASIC_FLAGS));
|
1410
1730
|
#endif
|
1731
|
+
|
1732
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
1733
|
+
rb_const_set(cMysql2Client, rb_intern("CONNECT_ATTRS"),
|
1734
|
+
LONG2NUM(CLIENT_CONNECT_ATTRS));
|
1735
|
+
#else
|
1736
|
+
/* HACK because MySQL 5.5 and earlier don't define this constant,
|
1737
|
+
* but we're using it in our default connection flags. */
|
1738
|
+
rb_const_set(cMysql2Client, rb_intern("CONNECT_ATTRS"),
|
1739
|
+
INT2NUM(0));
|
1740
|
+
#endif
|
1741
|
+
|
1742
|
+
#ifdef CLIENT_SESSION_TRACK
|
1743
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK"), INT2NUM(CLIENT_SESSION_TRACK));
|
1744
|
+
/* From mysql_com.h -- but stable from at least 5.7.4 through 8.0.20 */
|
1745
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_SYSTEM_VARIABLES"), INT2NUM(SESSION_TRACK_SYSTEM_VARIABLES));
|
1746
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_SCHEMA"), INT2NUM(SESSION_TRACK_SCHEMA));
|
1747
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_STATE_CHANGE"), INT2NUM(SESSION_TRACK_STATE_CHANGE));
|
1748
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_GTIDS"), INT2NUM(SESSION_TRACK_GTIDS));
|
1749
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_TRANSACTION_CHARACTERISTICS"), INT2NUM(SESSION_TRACK_TRANSACTION_CHARACTERISTICS));
|
1750
|
+
rb_const_set(cMysql2Client, rb_intern("SESSION_TRACK_TRANSACTION_STATE"), INT2NUM(SESSION_TRACK_TRANSACTION_STATE));
|
1751
|
+
#endif
|
1752
|
+
|
1753
|
+
#if defined(FULL_SSL_MODE_SUPPORT) // MySQL 5.6.36 and MySQL 5.7.11 and above
|
1754
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
|
1755
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_PREFERRED"), INT2NUM(SSL_MODE_PREFERRED));
|
1756
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(SSL_MODE_REQUIRED));
|
1757
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_CA"), INT2NUM(SSL_MODE_VERIFY_CA));
|
1758
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(SSL_MODE_VERIFY_IDENTITY));
|
1759
|
+
#else
|
1760
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_VERIFY_SERVER_CERT // MySQL 5.7.3 - 5.7.10 & MariaDB 10.x and later
|
1761
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(SSL_MODE_VERIFY_IDENTITY));
|
1762
|
+
#endif
|
1763
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE // MySQL 5.7.3 - 5.7.10 & MariaDB 10.x and later
|
1764
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
|
1765
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(SSL_MODE_REQUIRED));
|
1766
|
+
#endif
|
1767
|
+
#endif
|
1768
|
+
|
1769
|
+
#ifndef HAVE_CONST_SSL_MODE_DISABLED
|
1770
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(0));
|
1771
|
+
#endif
|
1772
|
+
#ifndef HAVE_CONST_SSL_MODE_PREFERRED
|
1773
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_PREFERRED"), INT2NUM(0));
|
1774
|
+
#endif
|
1775
|
+
#ifndef HAVE_CONST_SSL_MODE_REQUIRED
|
1776
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(0));
|
1777
|
+
#endif
|
1778
|
+
#ifndef HAVE_CONST_SSL_MODE_VERIFY_CA
|
1779
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_CA"), INT2NUM(0));
|
1780
|
+
#endif
|
1781
|
+
#ifndef HAVE_CONST_SSL_MODE_VERIFY_IDENTITY
|
1782
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(0));
|
1783
|
+
#endif
|
1784
|
+
}
|
1785
|
+
|
1786
|
+
#define flag_to_bool(f) ((client->server_status & f) ? Qtrue : Qfalse)
|
1787
|
+
|
1788
|
+
void rb_mysql_set_server_query_flags(MYSQL *client, VALUE result) {
|
1789
|
+
VALUE server_flags = rb_hash_new();
|
1790
|
+
|
1791
|
+
#ifdef HAVE_CONST_SERVER_QUERY_NO_GOOD_INDEX_USED
|
1792
|
+
rb_hash_aset(server_flags, sym_no_good_index_used, flag_to_bool(SERVER_QUERY_NO_GOOD_INDEX_USED));
|
1793
|
+
#else
|
1794
|
+
rb_hash_aset(server_flags, sym_no_good_index_used, Qnil);
|
1795
|
+
#endif
|
1796
|
+
|
1797
|
+
#ifdef HAVE_CONST_SERVER_QUERY_NO_INDEX_USED
|
1798
|
+
rb_hash_aset(server_flags, sym_no_index_used, flag_to_bool(SERVER_QUERY_NO_INDEX_USED));
|
1799
|
+
#else
|
1800
|
+
rb_hash_aset(server_flags, sym_no_index_used, Qnil);
|
1801
|
+
#endif
|
1802
|
+
|
1803
|
+
#ifdef HAVE_CONST_SERVER_QUERY_WAS_SLOW
|
1804
|
+
rb_hash_aset(server_flags, sym_query_was_slow, flag_to_bool(SERVER_QUERY_WAS_SLOW));
|
1805
|
+
#else
|
1806
|
+
rb_hash_aset(server_flags, sym_query_was_slow, Qnil);
|
1807
|
+
#endif
|
1808
|
+
|
1809
|
+
rb_iv_set(result, "@server_flags", server_flags);
|
1411
1810
|
}
|