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