mysql2 0.3.10 → 0.5.3
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 +7 -0
- data/CHANGELOG.md +1 -230
- data/LICENSE +21 -0
- data/README.md +405 -80
- data/ext/mysql2/client.c +1110 -335
- data/ext/mysql2/client.h +18 -32
- data/ext/mysql2/extconf.rb +228 -37
- data/ext/mysql2/infile.c +122 -0
- data/ext/mysql2/infile.h +1 -0
- data/ext/mysql2/mysql2_ext.c +3 -1
- data/ext/mysql2/mysql2_ext.h +18 -16
- data/ext/mysql2/mysql_enc_name_to_ruby.h +172 -0
- data/ext/mysql2/mysql_enc_to_ruby.h +310 -0
- data/ext/mysql2/result.c +671 -226
- data/ext/mysql2/result.h +15 -6
- data/ext/mysql2/statement.c +604 -0
- data/ext/mysql2/statement.h +17 -0
- data/ext/mysql2/wait_for_single_fd.h +2 -1
- data/lib/mysql2/client.rb +125 -212
- data/lib/mysql2/console.rb +5 -0
- data/lib/mysql2/em.rb +24 -8
- data/lib/mysql2/error.rb +93 -8
- data/lib/mysql2/field.rb +3 -0
- data/lib/mysql2/result.rb +2 -0
- data/lib/mysql2/statement.rb +11 -0
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +70 -5
- data/support/5072E1F5.asc +432 -0
- data/support/libmysql.def +219 -0
- data/support/mysql_enc_to_ruby.rb +86 -0
- data/support/ruby_enc_to_mysql.rb +63 -0
- metadata +45 -214
- data/.gitignore +0 -12
- data/.rspec +0 -3
- data/.rvmrc +0 -1
- data/.travis.yml +0 -7
- data/Gemfile +0 -3
- data/MIT-LICENSE +0 -20
- data/Rakefile +0 -5
- data/benchmark/active_record.rb +0 -51
- data/benchmark/active_record_threaded.rb +0 -42
- data/benchmark/allocations.rb +0 -33
- data/benchmark/escape.rb +0 -36
- data/benchmark/query_with_mysql_casting.rb +0 -80
- data/benchmark/query_without_mysql_casting.rb +0 -56
- data/benchmark/sequel.rb +0 -37
- data/benchmark/setup_db.rb +0 -119
- data/benchmark/threaded.rb +0 -44
- data/examples/eventmachine.rb +0 -21
- data/examples/threaded.rb +0 -20
- data/mysql2.gemspec +0 -29
- data/spec/em/em_spec.rb +0 -50
- data/spec/mysql2/client_spec.rb +0 -465
- data/spec/mysql2/error_spec.rb +0 -69
- data/spec/mysql2/result_spec.rb +0 -388
- data/spec/rcov.opts +0 -3
- data/spec/spec_helper.rb +0 -67
- data/tasks/benchmarks.rake +0 -20
- data/tasks/compile.rake +0 -71
- data/tasks/rspec.rake +0 -16
- data/tasks/vendor_mysql.rake +0 -40
data/ext/mysql2/client.c
CHANGED
@@ -1,32 +1,75 @@
|
|
1
1
|
#include <mysql2_ext.h>
|
2
|
-
|
2
|
+
|
3
|
+
#include <time.h>
|
3
4
|
#include <errno.h>
|
4
5
|
#ifndef _WIN32
|
6
|
+
#include <sys/types.h>
|
5
7
|
#include <sys/socket.h>
|
6
8
|
#endif
|
9
|
+
#ifndef _MSC_VER
|
10
|
+
#include <unistd.h>
|
11
|
+
#endif
|
12
|
+
#include <fcntl.h>
|
7
13
|
#include "wait_for_single_fd.h"
|
8
14
|
|
15
|
+
#include "mysql_enc_name_to_ruby.h"
|
16
|
+
|
9
17
|
VALUE cMysql2Client;
|
10
|
-
extern VALUE mMysql2, cMysql2Error;
|
11
|
-
static VALUE
|
12
|
-
static VALUE
|
13
|
-
static ID intern_merge,
|
18
|
+
extern VALUE mMysql2, cMysql2Error, cMysql2TimeoutError;
|
19
|
+
static VALUE sym_id, sym_version, sym_header_version, sym_async, sym_symbolize_keys, sym_as, sym_array, sym_stream;
|
20
|
+
static VALUE sym_no_good_index_used, sym_no_index_used, sym_query_was_slow;
|
21
|
+
static ID intern_brackets, intern_merge, intern_merge_bang, intern_new_with_args,
|
22
|
+
intern_current_query_options, intern_read_timeout;
|
23
|
+
|
24
|
+
#define REQUIRE_INITIALIZED(wrapper) \
|
25
|
+
if (!wrapper->initialized) { \
|
26
|
+
rb_raise(cMysql2Error, "MySQL client is not initialized"); \
|
27
|
+
}
|
14
28
|
|
15
|
-
#
|
16
|
-
|
17
|
-
|
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"); \
|
18
39
|
}
|
19
40
|
|
20
|
-
#define
|
21
|
-
wrapper
|
41
|
+
#define REQUIRE_NOT_CONNECTED(wrapper) \
|
42
|
+
REQUIRE_INITIALIZED(wrapper) \
|
43
|
+
if (CONNECTED(wrapper)) { \
|
44
|
+
rb_raise(cMysql2Error, "MySQL connection is already open"); \
|
45
|
+
}
|
22
46
|
|
23
|
-
|
24
|
-
|
25
|
-
|
47
|
+
/*
|
48
|
+
* compatability with mysql-connector-c, where LIBMYSQL_VERSION is the correct
|
49
|
+
* variable to use, but MYSQL_SERVER_VERSION gives the correct numbers when
|
50
|
+
* linking against the server itself
|
51
|
+
*/
|
52
|
+
#if defined(MARIADB_CLIENT_VERSION_STR)
|
53
|
+
#define MYSQL_LINK_VERSION MARIADB_CLIENT_VERSION_STR
|
54
|
+
#elif defined(LIBMYSQL_VERSION)
|
55
|
+
#define MYSQL_LINK_VERSION LIBMYSQL_VERSION
|
56
|
+
#else
|
57
|
+
#define MYSQL_LINK_VERSION MYSQL_SERVER_VERSION
|
58
|
+
#endif
|
59
|
+
|
60
|
+
/*
|
61
|
+
* compatibility with mysql-connector-c 6.1.x, and with MySQL 5.7.3 - 5.7.10.
|
62
|
+
*/
|
63
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
|
64
|
+
#define SSL_MODE_DISABLED 1
|
65
|
+
#define SSL_MODE_REQUIRED 3
|
66
|
+
#define HAVE_CONST_SSL_MODE_DISABLED
|
67
|
+
#define HAVE_CONST_SSL_MODE_REQUIRED
|
68
|
+
#endif
|
26
69
|
|
27
70
|
/*
|
28
71
|
* used to pass all arguments to mysql_real_connect while inside
|
29
|
-
*
|
72
|
+
* rb_thread_call_without_gvl
|
30
73
|
*/
|
31
74
|
struct nogvl_connect_args {
|
32
75
|
MYSQL *mysql;
|
@@ -41,14 +84,65 @@ struct nogvl_connect_args {
|
|
41
84
|
|
42
85
|
/*
|
43
86
|
* used to pass all arguments to mysql_send_query while inside
|
44
|
-
*
|
87
|
+
* rb_thread_call_without_gvl
|
45
88
|
*/
|
46
89
|
struct nogvl_send_query_args {
|
47
90
|
MYSQL *mysql;
|
48
91
|
VALUE sql;
|
92
|
+
const char *sql_ptr;
|
93
|
+
long sql_len;
|
49
94
|
mysql_client_wrapper *wrapper;
|
50
95
|
};
|
51
96
|
|
97
|
+
/*
|
98
|
+
* used to pass all arguments to mysql_select_db while inside
|
99
|
+
* rb_thread_call_without_gvl
|
100
|
+
*/
|
101
|
+
struct nogvl_select_db_args {
|
102
|
+
MYSQL *mysql;
|
103
|
+
char *db;
|
104
|
+
};
|
105
|
+
|
106
|
+
static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
|
107
|
+
unsigned long version = mysql_get_client_version();
|
108
|
+
|
109
|
+
if (version < 50703) {
|
110
|
+
rb_warn( "Your mysql client library does not support setting ssl_mode; full support comes with 5.7.11." );
|
111
|
+
return Qnil;
|
112
|
+
}
|
113
|
+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
|
114
|
+
GET_CLIENT(self);
|
115
|
+
int val = NUM2INT( setting );
|
116
|
+
// Either MySQL 5.7.3 - 5.7.10, or Connector/C 6.1.3 - 6.1.x
|
117
|
+
if ((version >= 50703 && version < 50711) || (version >= 60103 && version < 60200)) {
|
118
|
+
if (val == SSL_MODE_DISABLED || val == SSL_MODE_REQUIRED) {
|
119
|
+
my_bool b = ( val == SSL_MODE_REQUIRED );
|
120
|
+
int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b );
|
121
|
+
return INT2NUM(result);
|
122
|
+
} else {
|
123
|
+
rb_warn( "MySQL client libraries between 5.7.3 and 5.7.10 only support SSL_MODE_DISABLED and SSL_MODE_REQUIRED" );
|
124
|
+
return Qnil;
|
125
|
+
}
|
126
|
+
} else {
|
127
|
+
rb_warn( "Your mysql client library does not support ssl_mode as expected." );
|
128
|
+
return Qnil;
|
129
|
+
}
|
130
|
+
#endif
|
131
|
+
#ifdef FULL_SSL_MODE_SUPPORT
|
132
|
+
GET_CLIENT(self);
|
133
|
+
int val = NUM2INT( setting );
|
134
|
+
|
135
|
+
if (val != SSL_MODE_DISABLED && val != SSL_MODE_PREFERRED && val != SSL_MODE_REQUIRED && val != SSL_MODE_VERIFY_CA && val != SSL_MODE_VERIFY_IDENTITY) {
|
136
|
+
rb_raise(cMysql2Error, "ssl_mode= takes DISABLED, PREFERRED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY, you passed: %d", val );
|
137
|
+
}
|
138
|
+
int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_MODE, &val );
|
139
|
+
|
140
|
+
return INT2NUM(result);
|
141
|
+
#endif
|
142
|
+
#ifdef NO_SSL_MODE_SUPPORT
|
143
|
+
return Qnil;
|
144
|
+
#endif
|
145
|
+
}
|
52
146
|
/*
|
53
147
|
* non-blocking mysql_*() functions that we won't be wrapping since
|
54
148
|
* they do not appear to hit the network nor issue any interruptible
|
@@ -75,90 +169,148 @@ static void rb_mysql_client_mark(void * wrapper) {
|
|
75
169
|
mysql_client_wrapper * w = wrapper;
|
76
170
|
if (w) {
|
77
171
|
rb_gc_mark(w->encoding);
|
172
|
+
rb_gc_mark(w->active_thread);
|
78
173
|
}
|
79
174
|
}
|
80
175
|
|
81
176
|
static VALUE rb_raise_mysql2_error(mysql_client_wrapper *wrapper) {
|
82
177
|
VALUE rb_error_msg = rb_str_new2(mysql_error(wrapper->client));
|
83
178
|
VALUE rb_sql_state = rb_tainted_str_new2(mysql_sqlstate(wrapper->client));
|
84
|
-
|
85
|
-
rb_encoding *default_internal_enc = rb_default_internal_encoding();
|
86
|
-
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
|
179
|
+
VALUE e;
|
87
180
|
|
88
|
-
rb_enc_associate(rb_error_msg,
|
89
|
-
rb_enc_associate(rb_sql_state,
|
90
|
-
if (default_internal_enc) {
|
91
|
-
rb_error_msg = rb_str_export_to_enc(rb_error_msg, default_internal_enc);
|
92
|
-
rb_sql_state = rb_str_export_to_enc(rb_sql_state, default_internal_enc);
|
93
|
-
}
|
94
|
-
#endif
|
181
|
+
rb_enc_associate(rb_error_msg, rb_utf8_encoding());
|
182
|
+
rb_enc_associate(rb_sql_state, rb_usascii_encoding());
|
95
183
|
|
96
|
-
|
97
|
-
|
98
|
-
|
184
|
+
e = rb_funcall(cMysql2Error, intern_new_with_args, 4,
|
185
|
+
rb_error_msg,
|
186
|
+
LONG2FIX(wrapper->server_version),
|
187
|
+
UINT2NUM(mysql_errno(wrapper->client)),
|
188
|
+
rb_sql_state);
|
99
189
|
rb_exc_raise(e);
|
100
|
-
return Qnil;
|
101
190
|
}
|
102
191
|
|
103
|
-
static
|
192
|
+
static void *nogvl_init(void *ptr) {
|
104
193
|
MYSQL *client;
|
194
|
+
mysql_client_wrapper *wrapper = ptr;
|
105
195
|
|
106
196
|
/* may initialize embedded server and read /etc/services off disk */
|
107
|
-
client = mysql_init(
|
108
|
-
|
197
|
+
client = mysql_init(wrapper->client);
|
198
|
+
|
199
|
+
if (client) mysql2_set_local_infile(client, wrapper);
|
200
|
+
|
201
|
+
return (void*)(client ? Qtrue : Qfalse);
|
109
202
|
}
|
110
203
|
|
111
|
-
static
|
204
|
+
static void *nogvl_connect(void *ptr) {
|
112
205
|
struct nogvl_connect_args *args = ptr;
|
113
206
|
MYSQL *client;
|
114
207
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
args->client_flag);
|
120
|
-
} while (! client && errno == EINTR && (errno = 0) == 0);
|
208
|
+
client = mysql_real_connect(args->mysql, args->host,
|
209
|
+
args->user, args->passwd,
|
210
|
+
args->db, args->port, args->unix_socket,
|
211
|
+
args->client_flag);
|
121
212
|
|
122
|
-
return client ? Qtrue : Qfalse;
|
213
|
+
return (void *)(client ? Qtrue : Qfalse);
|
123
214
|
}
|
124
215
|
|
125
|
-
static VALUE nogvl_close(void *ptr) {
|
126
|
-
mysql_client_wrapper *wrapper;
|
127
216
|
#ifndef _WIN32
|
128
|
-
|
217
|
+
/*
|
218
|
+
* Redirect clientfd to /dev/null for mysql_close and SSL_close to write,
|
219
|
+
* shutdown, and close. The hack is needed to prevent shutdown() from breaking
|
220
|
+
* a socket that may be in use by the parent or other processes after fork.
|
221
|
+
*
|
222
|
+
* /dev/null is used to absorb writes; previously a dummy socket was used, but
|
223
|
+
* it could not abosrb writes and caused openssl to go into an infinite loop.
|
224
|
+
*
|
225
|
+
* Returns Qtrue or Qfalse (success or failure)
|
226
|
+
*
|
227
|
+
* Note: if this function is needed on Windows, use "nul" instead of "/dev/null"
|
228
|
+
*/
|
229
|
+
static VALUE invalidate_fd(int clientfd)
|
230
|
+
{
|
231
|
+
#ifdef O_CLOEXEC
|
232
|
+
/* Atomically set CLOEXEC on the new FD in case another thread forks */
|
233
|
+
int sockfd = open("/dev/null", O_RDWR | O_CLOEXEC);
|
234
|
+
#else
|
235
|
+
/* Well we don't have O_CLOEXEC, trigger the fallback code below */
|
236
|
+
int sockfd = -1;
|
129
237
|
#endif
|
130
|
-
|
131
|
-
if (
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
* we'll send a QUIT message to the server, but that message is more of a
|
136
|
-
* formality than a hard requirement since the socket is getting shutdown
|
137
|
-
* anyways, so ensure the socket write does not block our interpreter
|
138
|
-
*
|
139
|
-
*
|
140
|
-
* if the socket is dead we have no chance of blocking,
|
141
|
-
* so ignore any potential fcntl errors since they don't matter
|
238
|
+
|
239
|
+
if (sockfd < 0) {
|
240
|
+
/* Either O_CLOEXEC wasn't defined at compile time, or it was defined at
|
241
|
+
* compile time, but isn't available at run-time. So we'll just be quick
|
242
|
+
* about setting FD_CLOEXEC now.
|
142
243
|
*/
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
244
|
+
int flags;
|
245
|
+
sockfd = open("/dev/null", O_RDWR);
|
246
|
+
flags = fcntl(sockfd, F_GETFD);
|
247
|
+
/* Do the flags dance in case there are more defined flags in the future */
|
248
|
+
if (flags != -1) {
|
249
|
+
flags |= FD_CLOEXEC;
|
250
|
+
fcntl(sockfd, F_SETFD, flags);
|
251
|
+
}
|
252
|
+
}
|
253
|
+
|
254
|
+
if (sockfd < 0) {
|
255
|
+
/* Cannot raise here, because one or both of the following may be true:
|
256
|
+
* a) we have no GVL (in C Ruby)
|
257
|
+
* b) are running as a GC finalizer
|
258
|
+
*/
|
259
|
+
return Qfalse;
|
260
|
+
}
|
261
|
+
|
262
|
+
dup2(sockfd, clientfd);
|
263
|
+
close(sockfd);
|
264
|
+
|
265
|
+
return Qtrue;
|
266
|
+
}
|
267
|
+
#endif /* _WIN32 */
|
148
268
|
|
269
|
+
static void *nogvl_close(void *ptr) {
|
270
|
+
mysql_client_wrapper *wrapper = ptr;
|
271
|
+
|
272
|
+
if (!wrapper->closed) {
|
149
273
|
mysql_close(wrapper->client);
|
150
|
-
|
274
|
+
wrapper->closed = 1;
|
275
|
+
wrapper->reconnect_enabled = 0;
|
276
|
+
wrapper->active_thread = Qnil;
|
151
277
|
}
|
152
278
|
|
153
|
-
return
|
279
|
+
return NULL;
|
154
280
|
}
|
155
281
|
|
156
|
-
|
157
|
-
|
282
|
+
/* this is called during GC */
|
283
|
+
static void rb_mysql_client_free(void *ptr) {
|
284
|
+
mysql_client_wrapper *wrapper = ptr;
|
285
|
+
decr_mysql2_client(wrapper);
|
286
|
+
}
|
158
287
|
|
159
|
-
|
288
|
+
void decr_mysql2_client(mysql_client_wrapper *wrapper)
|
289
|
+
{
|
290
|
+
wrapper->refcount--;
|
160
291
|
|
161
|
-
|
292
|
+
if (wrapper->refcount == 0) {
|
293
|
+
#ifndef _WIN32
|
294
|
+
if (CONNECTED(wrapper) && !wrapper->automatic_close) {
|
295
|
+
/* The client is being garbage collected while connected. Prevent
|
296
|
+
* mysql_close() from sending a mysql-QUIT or from calling shutdown() on
|
297
|
+
* the socket by invalidating it. invalidate_fd() will drop this
|
298
|
+
* process's reference to the socket only, while a QUIT or shutdown()
|
299
|
+
* would render the underlying connection unusable, interrupting other
|
300
|
+
* processes which share this object across a fork().
|
301
|
+
*/
|
302
|
+
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
|
303
|
+
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely\n");
|
304
|
+
close(wrapper->client->net.fd);
|
305
|
+
}
|
306
|
+
wrapper->client->net.fd = -1;
|
307
|
+
}
|
308
|
+
#endif
|
309
|
+
|
310
|
+
nogvl_close(wrapper);
|
311
|
+
xfree(wrapper->client);
|
312
|
+
xfree(wrapper);
|
313
|
+
}
|
162
314
|
}
|
163
315
|
|
164
316
|
static VALUE allocate(VALUE klass) {
|
@@ -166,13 +318,26 @@ static VALUE allocate(VALUE klass) {
|
|
166
318
|
mysql_client_wrapper * wrapper;
|
167
319
|
obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
|
168
320
|
wrapper->encoding = Qnil;
|
169
|
-
wrapper->
|
321
|
+
wrapper->active_thread = Qnil;
|
322
|
+
wrapper->automatic_close = 1;
|
323
|
+
wrapper->server_version = 0;
|
170
324
|
wrapper->reconnect_enabled = 0;
|
171
|
-
wrapper->
|
172
|
-
wrapper->
|
325
|
+
wrapper->connect_timeout = 0;
|
326
|
+
wrapper->initialized = 0; /* means that that the wrapper is initialized */
|
327
|
+
wrapper->refcount = 1;
|
328
|
+
wrapper->closed = 0;
|
329
|
+
wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
|
330
|
+
|
173
331
|
return obj;
|
174
332
|
}
|
175
333
|
|
334
|
+
/* call-seq:
|
335
|
+
* Mysql2::Client.escape(string)
|
336
|
+
*
|
337
|
+
* Escape +string+ so that it may be used in a SQL statement.
|
338
|
+
* Note that this escape method is not connection encoding aware.
|
339
|
+
* If you need encoding support use Mysql2::Client#escape instead.
|
340
|
+
*/
|
176
341
|
static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
|
177
342
|
unsigned char *newStr;
|
178
343
|
VALUE rb_str;
|
@@ -181,83 +346,180 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
|
|
181
346
|
Check_Type(str, T_STRING);
|
182
347
|
|
183
348
|
oldLen = RSTRING_LEN(str);
|
184
|
-
newStr =
|
349
|
+
newStr = xmalloc(oldLen*2+1);
|
185
350
|
|
186
|
-
newLen = mysql_escape_string((char *)newStr,
|
351
|
+
newLen = mysql_escape_string((char *)newStr, RSTRING_PTR(str), oldLen);
|
187
352
|
if (newLen == oldLen) {
|
188
|
-
|
189
|
-
|
353
|
+
/* no need to return a new ruby string if nothing changed */
|
354
|
+
xfree(newStr);
|
190
355
|
return str;
|
191
356
|
} else {
|
192
357
|
rb_str = rb_str_new((const char*)newStr, newLen);
|
193
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
194
358
|
rb_enc_copy(rb_str, str);
|
195
|
-
|
196
|
-
free(newStr);
|
359
|
+
xfree(newStr);
|
197
360
|
return rb_str;
|
198
361
|
}
|
199
362
|
}
|
200
363
|
|
201
|
-
static VALUE
|
364
|
+
static VALUE rb_mysql_client_warning_count(VALUE self) {
|
365
|
+
unsigned int warning_count;
|
366
|
+
GET_CLIENT(self);
|
367
|
+
|
368
|
+
warning_count = mysql_warning_count(wrapper->client);
|
369
|
+
|
370
|
+
return UINT2NUM(warning_count);
|
371
|
+
}
|
372
|
+
|
373
|
+
static VALUE rb_mysql_info(VALUE self) {
|
374
|
+
const char *info;
|
375
|
+
VALUE rb_str;
|
376
|
+
GET_CLIENT(self);
|
377
|
+
|
378
|
+
info = mysql_info(wrapper->client);
|
379
|
+
|
380
|
+
if (info == NULL) {
|
381
|
+
return Qnil;
|
382
|
+
}
|
383
|
+
|
384
|
+
rb_str = rb_str_new2(info);
|
385
|
+
rb_enc_associate(rb_str, rb_utf8_encoding());
|
386
|
+
|
387
|
+
return rb_str;
|
388
|
+
}
|
389
|
+
|
390
|
+
static VALUE rb_mysql_get_ssl_cipher(VALUE self)
|
391
|
+
{
|
392
|
+
const char *cipher;
|
393
|
+
VALUE rb_str;
|
394
|
+
GET_CLIENT(self);
|
395
|
+
|
396
|
+
cipher = mysql_get_ssl_cipher(wrapper->client);
|
397
|
+
|
398
|
+
if (cipher == NULL) {
|
399
|
+
return Qnil;
|
400
|
+
}
|
401
|
+
|
402
|
+
rb_str = rb_str_new2(cipher);
|
403
|
+
rb_enc_associate(rb_str, rb_utf8_encoding());
|
404
|
+
|
405
|
+
return rb_str;
|
406
|
+
}
|
407
|
+
|
408
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
409
|
+
static int opt_connect_attr_add_i(VALUE key, VALUE value, VALUE arg)
|
410
|
+
{
|
411
|
+
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)arg;
|
412
|
+
rb_encoding *enc = rb_to_encoding(wrapper->encoding);
|
413
|
+
key = rb_str_export_to_enc(key, enc);
|
414
|
+
value = rb_str_export_to_enc(value, enc);
|
415
|
+
|
416
|
+
mysql_options4(wrapper->client, MYSQL_OPT_CONNECT_ATTR_ADD, StringValueCStr(key), StringValueCStr(value));
|
417
|
+
return ST_CONTINUE;
|
418
|
+
}
|
419
|
+
#endif
|
420
|
+
|
421
|
+
static VALUE rb_mysql_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags, VALUE conn_attrs) {
|
202
422
|
struct nogvl_connect_args args;
|
423
|
+
time_t start_time, end_time, elapsed_time, connect_timeout;
|
424
|
+
VALUE rv;
|
203
425
|
GET_CLIENT(self);
|
204
426
|
|
205
|
-
args.host
|
206
|
-
args.unix_socket = NIL_P(socket)
|
207
|
-
args.port
|
208
|
-
args.user
|
209
|
-
args.passwd
|
210
|
-
args.db
|
211
|
-
args.mysql
|
427
|
+
args.host = NIL_P(host) ? NULL : StringValueCStr(host);
|
428
|
+
args.unix_socket = NIL_P(socket) ? NULL : StringValueCStr(socket);
|
429
|
+
args.port = NIL_P(port) ? 0 : NUM2INT(port);
|
430
|
+
args.user = NIL_P(user) ? NULL : StringValueCStr(user);
|
431
|
+
args.passwd = NIL_P(pass) ? NULL : StringValueCStr(pass);
|
432
|
+
args.db = NIL_P(database) ? NULL : StringValueCStr(database);
|
433
|
+
args.mysql = wrapper->client;
|
212
434
|
args.client_flag = NUM2ULONG(flags);
|
213
435
|
|
214
|
-
|
215
|
-
|
216
|
-
|
436
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
437
|
+
mysql_options(wrapper->client, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
|
438
|
+
rb_hash_foreach(conn_attrs, opt_connect_attr_add_i, (VALUE)wrapper);
|
439
|
+
#endif
|
440
|
+
|
441
|
+
if (wrapper->connect_timeout)
|
442
|
+
time(&start_time);
|
443
|
+
rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0);
|
444
|
+
if (rv == Qfalse) {
|
445
|
+
while (rv == Qfalse && errno == EINTR) {
|
446
|
+
if (wrapper->connect_timeout) {
|
447
|
+
time(&end_time);
|
448
|
+
/* avoid long connect timeout from system time changes */
|
449
|
+
if (end_time < start_time)
|
450
|
+
start_time = end_time;
|
451
|
+
elapsed_time = end_time - start_time;
|
452
|
+
/* avoid an early timeout due to time truncating milliseconds off the start time */
|
453
|
+
if (elapsed_time > 0)
|
454
|
+
elapsed_time--;
|
455
|
+
if (elapsed_time >= (time_t)wrapper->connect_timeout)
|
456
|
+
break;
|
457
|
+
connect_timeout = wrapper->connect_timeout - elapsed_time;
|
458
|
+
mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
|
459
|
+
}
|
460
|
+
errno = 0;
|
461
|
+
rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0);
|
462
|
+
}
|
463
|
+
/* restore the connect timeout for reconnecting */
|
464
|
+
if (wrapper->connect_timeout)
|
465
|
+
mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &wrapper->connect_timeout);
|
466
|
+
if (rv == Qfalse)
|
467
|
+
rb_raise_mysql2_error(wrapper);
|
217
468
|
}
|
218
469
|
|
470
|
+
wrapper->server_version = mysql_get_server_version(wrapper->client);
|
219
471
|
return self;
|
220
472
|
}
|
221
473
|
|
222
474
|
/*
|
223
|
-
* Immediately disconnect from the server
|
475
|
+
* Immediately disconnect from the server; normally the garbage collector
|
224
476
|
* will disconnect automatically when a connection is no longer needed.
|
225
477
|
* Explicitly closing this will free up server resources sooner than waiting
|
226
478
|
* for the garbage collector.
|
479
|
+
*
|
480
|
+
* @return [nil]
|
227
481
|
*/
|
228
482
|
static VALUE rb_mysql_client_close(VALUE self) {
|
229
483
|
GET_CLIENT(self);
|
230
484
|
|
231
|
-
if (
|
232
|
-
|
485
|
+
if (wrapper->client) {
|
486
|
+
rb_thread_call_without_gvl(nogvl_close, wrapper, RUBY_UBF_IO, 0);
|
233
487
|
}
|
234
488
|
|
235
489
|
return Qnil;
|
236
490
|
}
|
237
491
|
|
492
|
+
/* call-seq:
|
493
|
+
* client.closed?
|
494
|
+
*
|
495
|
+
* @return [Boolean]
|
496
|
+
*/
|
497
|
+
static VALUE rb_mysql_client_closed(VALUE self) {
|
498
|
+
GET_CLIENT(self);
|
499
|
+
return CONNECTED(wrapper) ? Qfalse : Qtrue;
|
500
|
+
}
|
501
|
+
|
238
502
|
/*
|
239
503
|
* mysql_send_query is unlikely to block since most queries are small
|
240
504
|
* enough to fit in a socket buffer, but sometimes large UPDATE and
|
241
505
|
* INSERTs will cause the process to block
|
242
506
|
*/
|
243
|
-
static
|
507
|
+
static void *nogvl_send_query(void *ptr) {
|
244
508
|
struct nogvl_send_query_args *args = ptr;
|
245
509
|
int rv;
|
246
|
-
const char *sql = StringValuePtr(args->sql);
|
247
|
-
long sql_len = RSTRING_LEN(args->sql);
|
248
510
|
|
249
|
-
rv = mysql_send_query(args->mysql,
|
511
|
+
rv = mysql_send_query(args->mysql, args->sql_ptr, args->sql_len);
|
250
512
|
|
251
|
-
return rv == 0 ? Qtrue : Qfalse;
|
513
|
+
return (void*)(rv == 0 ? Qtrue : Qfalse);
|
252
514
|
}
|
253
515
|
|
254
516
|
static VALUE do_send_query(void *args) {
|
255
517
|
struct nogvl_send_query_args *query_args = args;
|
256
518
|
mysql_client_wrapper *wrapper = query_args->wrapper;
|
257
|
-
if (
|
258
|
-
|
259
|
-
|
260
|
-
|
519
|
+
if ((VALUE)rb_thread_call_without_gvl(nogvl_send_query, args, RUBY_UBF_IO, 0) == Qfalse) {
|
520
|
+
/* an error occurred, we're not active anymore */
|
521
|
+
wrapper->active_thread = Qnil;
|
522
|
+
rb_raise_mysql2_error(wrapper);
|
261
523
|
}
|
262
524
|
return Qnil;
|
263
525
|
}
|
@@ -267,64 +529,85 @@ static VALUE do_send_query(void *args) {
|
|
267
529
|
* response can overflow the socket buffers and cause us to eventually
|
268
530
|
* block while calling mysql_read_query_result
|
269
531
|
*/
|
270
|
-
static
|
532
|
+
static void *nogvl_read_query_result(void *ptr) {
|
271
533
|
MYSQL * client = ptr;
|
272
534
|
my_bool res = mysql_read_query_result(client);
|
273
535
|
|
274
|
-
return res == 0 ? Qtrue : Qfalse;
|
536
|
+
return (void *)(res == 0 ? Qtrue : Qfalse);
|
275
537
|
}
|
276
538
|
|
277
|
-
|
278
|
-
|
279
|
-
mysql_client_wrapper *wrapper;
|
539
|
+
static void *nogvl_do_result(void *ptr, char use_result) {
|
540
|
+
mysql_client_wrapper *wrapper = ptr;
|
280
541
|
MYSQL_RES *result;
|
281
542
|
|
282
|
-
|
283
|
-
|
543
|
+
if (use_result) {
|
544
|
+
result = mysql_use_result(wrapper->client);
|
545
|
+
} else {
|
546
|
+
result = mysql_store_result(wrapper->client);
|
547
|
+
}
|
284
548
|
|
285
|
-
|
286
|
-
|
287
|
-
wrapper->
|
549
|
+
/* once our result is stored off, this connection is
|
550
|
+
ready for another command to be issued */
|
551
|
+
wrapper->active_thread = Qnil;
|
288
552
|
|
289
|
-
return
|
553
|
+
return result;
|
290
554
|
}
|
291
555
|
|
556
|
+
/* mysql_store_result may (unlikely) read rows off the socket */
|
557
|
+
static void *nogvl_store_result(void *ptr) {
|
558
|
+
return nogvl_do_result(ptr, 0);
|
559
|
+
}
|
560
|
+
|
561
|
+
static void *nogvl_use_result(void *ptr) {
|
562
|
+
return nogvl_do_result(ptr, 1);
|
563
|
+
}
|
564
|
+
|
565
|
+
/* call-seq:
|
566
|
+
* client.async_result
|
567
|
+
*
|
568
|
+
* Returns the result for the last async issued query.
|
569
|
+
*/
|
292
570
|
static VALUE rb_mysql_client_async_result(VALUE self) {
|
293
571
|
MYSQL_RES * result;
|
294
572
|
VALUE resultObj;
|
295
|
-
|
296
|
-
mysql2_result_wrapper * result_wrapper;
|
297
|
-
#endif
|
573
|
+
VALUE current, is_streaming;
|
298
574
|
GET_CLIENT(self);
|
299
575
|
|
300
|
-
|
301
|
-
if (
|
576
|
+
/* if we're not waiting on a result, do nothing */
|
577
|
+
if (NIL_P(wrapper->active_thread))
|
302
578
|
return Qnil;
|
303
579
|
|
304
|
-
|
305
|
-
if (
|
306
|
-
|
307
|
-
|
308
|
-
|
580
|
+
REQUIRE_CONNECTED(wrapper);
|
581
|
+
if ((VALUE)rb_thread_call_without_gvl(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
|
582
|
+
/* an error occurred, mark this connection inactive */
|
583
|
+
wrapper->active_thread = Qnil;
|
584
|
+
rb_raise_mysql2_error(wrapper);
|
309
585
|
}
|
310
586
|
|
311
|
-
|
587
|
+
is_streaming = rb_hash_aref(rb_ivar_get(self, intern_current_query_options), sym_stream);
|
588
|
+
if (is_streaming == Qtrue) {
|
589
|
+
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_use_result, wrapper, RUBY_UBF_IO, 0);
|
590
|
+
} else {
|
591
|
+
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
|
592
|
+
}
|
312
593
|
|
313
594
|
if (result == NULL) {
|
314
|
-
if (
|
595
|
+
if (mysql_errno(wrapper->client) != 0) {
|
596
|
+
wrapper->active_thread = Qnil;
|
315
597
|
rb_raise_mysql2_error(wrapper);
|
316
598
|
}
|
599
|
+
/* no data and no error, so query was not a SELECT */
|
317
600
|
return Qnil;
|
318
601
|
}
|
319
602
|
|
320
|
-
|
321
|
-
|
322
|
-
|
603
|
+
// Duplicate the options hash and put the copy in the Result object
|
604
|
+
current = rb_hash_dup(rb_ivar_get(self, intern_current_query_options));
|
605
|
+
(void)RB_GC_GUARD(current);
|
606
|
+
Check_Type(current, T_HASH);
|
607
|
+
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
|
608
|
+
|
609
|
+
rb_mysql_set_server_query_flags(wrapper->client, resultObj);
|
323
610
|
|
324
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
325
|
-
GetMysql2Result(resultObj, result_wrapper);
|
326
|
-
result_wrapper->encoding = wrapper->encoding;
|
327
|
-
#endif
|
328
611
|
return resultObj;
|
329
612
|
}
|
330
613
|
|
@@ -337,36 +620,39 @@ struct async_query_args {
|
|
337
620
|
static VALUE disconnect_and_raise(VALUE self, VALUE error) {
|
338
621
|
GET_CLIENT(self);
|
339
622
|
|
340
|
-
wrapper->
|
341
|
-
wrapper->active = 0;
|
623
|
+
wrapper->active_thread = Qnil;
|
342
624
|
|
343
|
-
|
344
|
-
|
345
|
-
|
625
|
+
/* Invalidate the MySQL socket to prevent further communication.
|
626
|
+
* The GC will come along later and call mysql_close to free it.
|
627
|
+
*/
|
628
|
+
if (CONNECTED(wrapper)) {
|
629
|
+
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
|
630
|
+
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, closing unsafely\n");
|
631
|
+
close(wrapper->client->net.fd);
|
632
|
+
}
|
633
|
+
wrapper->client->net.fd = -1;
|
634
|
+
}
|
346
635
|
|
347
636
|
rb_exc_raise(error);
|
348
|
-
|
349
|
-
return Qnil;
|
350
637
|
}
|
351
638
|
|
352
639
|
static VALUE do_query(void *args) {
|
353
|
-
struct async_query_args *async_args;
|
640
|
+
struct async_query_args *async_args = args;
|
354
641
|
struct timeval tv;
|
355
|
-
struct timeval*
|
642
|
+
struct timeval *tvp;
|
356
643
|
long int sec;
|
357
644
|
int retval;
|
358
645
|
VALUE read_timeout;
|
359
646
|
|
360
|
-
|
361
|
-
read_timeout = rb_iv_get(async_args->self, "@read_timeout");
|
647
|
+
read_timeout = rb_ivar_get(async_args->self, intern_read_timeout);
|
362
648
|
|
363
649
|
tvp = NULL;
|
364
650
|
if (!NIL_P(read_timeout)) {
|
365
651
|
Check_Type(read_timeout, T_FIXNUM);
|
366
652
|
tvp = &tv;
|
367
653
|
sec = FIX2INT(read_timeout);
|
368
|
-
|
369
|
-
|
654
|
+
/* TODO: support partial seconds?
|
655
|
+
also, this check is here for sanity, we also check up in Ruby */
|
370
656
|
if (sec >= 0) {
|
371
657
|
tvp->tv_sec = sec;
|
372
658
|
} else {
|
@@ -379,7 +665,7 @@ static VALUE do_query(void *args) {
|
|
379
665
|
retval = rb_wait_for_single_fd(async_args->fd, RB_WAITFD_IN, tvp);
|
380
666
|
|
381
667
|
if (retval == 0) {
|
382
|
-
rb_raise(
|
668
|
+
rb_raise(cMysql2TimeoutError, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
|
383
669
|
}
|
384
670
|
|
385
671
|
if (retval < 0) {
|
@@ -393,210 +679,359 @@ static VALUE do_query(void *args) {
|
|
393
679
|
|
394
680
|
return Qnil;
|
395
681
|
}
|
682
|
+
#endif
|
683
|
+
|
684
|
+
static VALUE disconnect_and_mark_inactive(VALUE self) {
|
685
|
+
GET_CLIENT(self);
|
686
|
+
|
687
|
+
/* Check if execution terminated while result was still being read. */
|
688
|
+
if (!NIL_P(wrapper->active_thread)) {
|
689
|
+
if (CONNECTED(wrapper)) {
|
690
|
+
/* Invalidate the MySQL socket to prevent further communication. */
|
691
|
+
#ifndef _WIN32
|
692
|
+
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
|
693
|
+
rb_warn("mysql2 failed to invalidate FD safely, closing unsafely\n");
|
694
|
+
close(wrapper->client->net.fd);
|
695
|
+
}
|
396
696
|
#else
|
397
|
-
|
398
|
-
|
399
|
-
|
697
|
+
close(wrapper->client->net.fd);
|
698
|
+
#endif
|
699
|
+
wrapper->client->net.fd = -1;
|
700
|
+
}
|
701
|
+
/* Skip mysql client check performed before command execution. */
|
702
|
+
wrapper->client->status = MYSQL_STATUS_READY;
|
703
|
+
wrapper->active_thread = Qnil;
|
704
|
+
}
|
400
705
|
|
401
|
-
|
706
|
+
return Qnil;
|
707
|
+
}
|
402
708
|
|
709
|
+
void rb_mysql_client_set_active_thread(VALUE self) {
|
710
|
+
VALUE thread_current = rb_thread_current();
|
403
711
|
GET_CLIENT(self);
|
404
712
|
|
405
|
-
if
|
406
|
-
|
407
|
-
//
|
408
|
-
|
409
|
-
|
410
|
-
|
713
|
+
// see if this connection is still waiting on a result from a previous query
|
714
|
+
if (NIL_P(wrapper->active_thread)) {
|
715
|
+
// mark this connection active
|
716
|
+
wrapper->active_thread = thread_current;
|
717
|
+
} else if (wrapper->active_thread == thread_current) {
|
718
|
+
rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
|
719
|
+
} else {
|
720
|
+
VALUE inspect = rb_inspect(wrapper->active_thread);
|
721
|
+
const char *thr = StringValueCStr(inspect);
|
411
722
|
|
412
|
-
|
723
|
+
rb_raise(cMysql2Error, "This connection is in use by: %s", thr);
|
724
|
+
}
|
725
|
+
}
|
726
|
+
|
727
|
+
/* call-seq:
|
728
|
+
* client.abandon_results!
|
729
|
+
*
|
730
|
+
* When using MULTI_STATEMENTS support, calling this will throw
|
731
|
+
* away any unprocessed results as fast as it can in order to
|
732
|
+
* put the connection back into a state where queries can be issued
|
733
|
+
* again.
|
734
|
+
*/
|
735
|
+
static VALUE rb_mysql_client_abandon_results(VALUE self) {
|
736
|
+
MYSQL_RES *result;
|
737
|
+
int ret;
|
738
|
+
|
739
|
+
GET_CLIENT(self);
|
740
|
+
|
741
|
+
while (mysql_more_results(wrapper->client) == 1) {
|
742
|
+
ret = mysql_next_result(wrapper->client);
|
743
|
+
if (ret > 0) {
|
744
|
+
rb_raise_mysql2_error(wrapper);
|
745
|
+
}
|
746
|
+
|
747
|
+
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
|
748
|
+
|
749
|
+
if (result != NULL) {
|
750
|
+
mysql_free_result(result);
|
751
|
+
}
|
413
752
|
}
|
414
753
|
|
415
754
|
return Qnil;
|
416
755
|
}
|
417
|
-
#endif
|
418
756
|
|
419
|
-
|
757
|
+
/* call-seq:
|
758
|
+
* client.query(sql, options = {})
|
759
|
+
*
|
760
|
+
* Query the database with +sql+, with optional +options+. For the possible
|
761
|
+
* options, see default_query_options on the Mysql2::Client class.
|
762
|
+
*/
|
763
|
+
static VALUE rb_mysql_query(VALUE self, VALUE sql, VALUE current) {
|
420
764
|
#ifndef _WIN32
|
421
765
|
struct async_query_args async_args;
|
422
766
|
#endif
|
423
767
|
struct nogvl_send_query_args args;
|
424
|
-
int async = 0;
|
425
|
-
VALUE opts, defaults;
|
426
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
427
|
-
rb_encoding *conn_enc;
|
428
|
-
#endif
|
429
768
|
GET_CLIENT(self);
|
430
769
|
|
431
|
-
|
770
|
+
REQUIRE_CONNECTED(wrapper);
|
432
771
|
args.mysql = wrapper->client;
|
433
772
|
|
773
|
+
(void)RB_GC_GUARD(current);
|
774
|
+
Check_Type(current, T_HASH);
|
775
|
+
rb_ivar_set(self, intern_current_query_options, current);
|
434
776
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
if (rb_hash_aref(opts, sym_async) == Qtrue) {
|
441
|
-
async = 1;
|
442
|
-
}
|
443
|
-
} else {
|
444
|
-
opts = defaults;
|
445
|
-
}
|
446
|
-
|
447
|
-
Check_Type(args.sql, T_STRING);
|
448
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
449
|
-
conn_enc = rb_to_encoding(wrapper->encoding);
|
450
|
-
// ensure the string is in the encoding the connection is expecting
|
451
|
-
args.sql = rb_str_export_to_enc(args.sql, conn_enc);
|
452
|
-
#endif
|
453
|
-
|
454
|
-
// see if this connection is still waiting on a result from a previous query
|
455
|
-
if (wrapper->active == 0) {
|
456
|
-
// mark this connection active
|
457
|
-
wrapper->active = 1;
|
458
|
-
} else {
|
459
|
-
rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
|
460
|
-
}
|
461
|
-
|
777
|
+
Check_Type(sql, T_STRING);
|
778
|
+
/* ensure the string is in the encoding the connection is expecting */
|
779
|
+
args.sql = rb_str_export_to_enc(sql, rb_to_encoding(wrapper->encoding));
|
780
|
+
args.sql_ptr = RSTRING_PTR(args.sql);
|
781
|
+
args.sql_len = RSTRING_LEN(args.sql);
|
462
782
|
args.wrapper = wrapper;
|
463
783
|
|
784
|
+
rb_mysql_client_set_active_thread(self);
|
785
|
+
|
464
786
|
#ifndef _WIN32
|
465
787
|
rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);
|
466
788
|
|
467
|
-
if (
|
789
|
+
if (rb_hash_aref(current, sym_async) == Qtrue) {
|
790
|
+
return Qnil;
|
791
|
+
} else {
|
468
792
|
async_args.fd = wrapper->client->net.fd;
|
469
793
|
async_args.self = self;
|
470
794
|
|
471
795
|
rb_rescue2(do_query, (VALUE)&async_args, disconnect_and_raise, self, rb_eException, (VALUE)0);
|
472
796
|
|
473
|
-
return rb_mysql_client_async_result
|
474
|
-
} else {
|
475
|
-
return Qnil;
|
797
|
+
return rb_ensure(rb_mysql_client_async_result, self, disconnect_and_mark_inactive, self);
|
476
798
|
}
|
477
799
|
#else
|
478
800
|
do_send_query(&args);
|
479
801
|
|
480
|
-
|
481
|
-
return rb_ensure(rb_mysql_client_async_result, self,
|
802
|
+
/* this will just block until the result is ready */
|
803
|
+
return rb_ensure(rb_mysql_client_async_result, self, disconnect_and_mark_inactive, self);
|
482
804
|
#endif
|
483
805
|
}
|
484
806
|
|
807
|
+
/* call-seq:
|
808
|
+
* client.escape(string)
|
809
|
+
*
|
810
|
+
* Escape +string+ so that it may be used in a SQL statement.
|
811
|
+
*/
|
485
812
|
static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
486
813
|
unsigned char *newStr;
|
487
814
|
VALUE rb_str;
|
488
815
|
unsigned long newLen, oldLen;
|
489
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
490
816
|
rb_encoding *default_internal_enc;
|
491
817
|
rb_encoding *conn_enc;
|
492
|
-
#endif
|
493
818
|
GET_CLIENT(self);
|
494
819
|
|
495
|
-
|
820
|
+
REQUIRE_CONNECTED(wrapper);
|
496
821
|
Check_Type(str, T_STRING);
|
497
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
498
822
|
default_internal_enc = rb_default_internal_encoding();
|
499
823
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
500
|
-
|
824
|
+
/* ensure the string is in the encoding the connection is expecting */
|
501
825
|
str = rb_str_export_to_enc(str, conn_enc);
|
502
|
-
#endif
|
503
826
|
|
504
827
|
oldLen = RSTRING_LEN(str);
|
505
|
-
newStr =
|
828
|
+
newStr = xmalloc(oldLen*2+1);
|
506
829
|
|
507
|
-
newLen = mysql_real_escape_string(wrapper->client, (char *)newStr,
|
830
|
+
newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, RSTRING_PTR(str), oldLen);
|
508
831
|
if (newLen == oldLen) {
|
509
|
-
|
510
|
-
|
832
|
+
/* no need to return a new ruby string if nothing changed */
|
833
|
+
if (default_internal_enc) {
|
834
|
+
str = rb_str_export_to_enc(str, default_internal_enc);
|
835
|
+
}
|
836
|
+
xfree(newStr);
|
511
837
|
return str;
|
512
838
|
} else {
|
513
839
|
rb_str = rb_str_new((const char*)newStr, newLen);
|
514
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
515
840
|
rb_enc_associate(rb_str, conn_enc);
|
516
841
|
if (default_internal_enc) {
|
517
842
|
rb_str = rb_str_export_to_enc(rb_str, default_internal_enc);
|
518
843
|
}
|
519
|
-
|
520
|
-
free(newStr);
|
844
|
+
xfree(newStr);
|
521
845
|
return rb_str;
|
522
846
|
}
|
523
847
|
}
|
524
848
|
|
525
|
-
static VALUE
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
849
|
+
static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
850
|
+
int result;
|
851
|
+
const void *retval = NULL;
|
852
|
+
unsigned int intval = 0;
|
853
|
+
const char * charval = NULL;
|
854
|
+
my_bool boolval;
|
855
|
+
|
531
856
|
GET_CLIENT(self);
|
532
|
-
version = rb_hash_new();
|
533
857
|
|
534
|
-
|
535
|
-
|
536
|
-
|
858
|
+
REQUIRE_NOT_CONNECTED(wrapper);
|
859
|
+
|
860
|
+
if (NIL_P(value))
|
861
|
+
return Qfalse;
|
862
|
+
|
863
|
+
switch(opt) {
|
864
|
+
case MYSQL_OPT_CONNECT_TIMEOUT:
|
865
|
+
intval = NUM2UINT(value);
|
866
|
+
retval = &intval;
|
867
|
+
break;
|
868
|
+
|
869
|
+
case MYSQL_OPT_READ_TIMEOUT:
|
870
|
+
intval = NUM2UINT(value);
|
871
|
+
retval = &intval;
|
872
|
+
break;
|
873
|
+
|
874
|
+
case MYSQL_OPT_WRITE_TIMEOUT:
|
875
|
+
intval = NUM2UINT(value);
|
876
|
+
retval = &intval;
|
877
|
+
break;
|
878
|
+
|
879
|
+
case MYSQL_OPT_LOCAL_INFILE:
|
880
|
+
intval = (value == Qfalse ? 0 : 1);
|
881
|
+
retval = &intval;
|
882
|
+
break;
|
883
|
+
|
884
|
+
case MYSQL_OPT_RECONNECT:
|
885
|
+
boolval = (value == Qfalse ? 0 : 1);
|
886
|
+
retval = &boolval;
|
887
|
+
break;
|
888
|
+
|
889
|
+
#ifdef MYSQL_SECURE_AUTH
|
890
|
+
case MYSQL_SECURE_AUTH:
|
891
|
+
boolval = (value == Qfalse ? 0 : 1);
|
892
|
+
retval = &boolval;
|
893
|
+
break;
|
537
894
|
#endif
|
538
895
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
896
|
+
case MYSQL_READ_DEFAULT_FILE:
|
897
|
+
charval = (const char *)StringValueCStr(value);
|
898
|
+
retval = charval;
|
899
|
+
break;
|
900
|
+
|
901
|
+
case MYSQL_READ_DEFAULT_GROUP:
|
902
|
+
charval = (const char *)StringValueCStr(value);
|
903
|
+
retval = charval;
|
904
|
+
break;
|
905
|
+
|
906
|
+
case MYSQL_INIT_COMMAND:
|
907
|
+
charval = (const char *)StringValueCStr(value);
|
908
|
+
retval = charval;
|
909
|
+
break;
|
910
|
+
|
911
|
+
case MYSQL_DEFAULT_AUTH:
|
912
|
+
charval = (const char *)StringValueCStr(value);
|
913
|
+
retval = charval;
|
914
|
+
break;
|
915
|
+
|
916
|
+
#ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
|
917
|
+
case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
|
918
|
+
boolval = (value == Qfalse ? 0 : 1);
|
919
|
+
retval = &boolval;
|
920
|
+
break;
|
546
921
|
#endif
|
547
|
-
|
548
|
-
|
922
|
+
|
923
|
+
default:
|
924
|
+
return Qfalse;
|
925
|
+
}
|
926
|
+
|
927
|
+
result = mysql_options(wrapper->client, opt, retval);
|
928
|
+
|
929
|
+
/* Zero means success */
|
930
|
+
if (result != 0) {
|
931
|
+
rb_warn("%s\n", mysql_error(wrapper->client));
|
932
|
+
} else {
|
933
|
+
/* Special case for options that are stored in the wrapper struct */
|
934
|
+
switch (opt) {
|
935
|
+
case MYSQL_OPT_RECONNECT:
|
936
|
+
wrapper->reconnect_enabled = boolval;
|
937
|
+
break;
|
938
|
+
case MYSQL_OPT_CONNECT_TIMEOUT:
|
939
|
+
wrapper->connect_timeout = intval;
|
940
|
+
break;
|
941
|
+
}
|
942
|
+
}
|
943
|
+
|
944
|
+
return (result == 0) ? Qtrue : Qfalse;
|
945
|
+
}
|
946
|
+
|
947
|
+
/* call-seq:
|
948
|
+
* client.info
|
949
|
+
*
|
950
|
+
* Returns a string that represents the client library version.
|
951
|
+
*/
|
952
|
+
static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE klass) {
|
953
|
+
VALUE version_info, version, header_version;
|
954
|
+
version_info = rb_hash_new();
|
955
|
+
|
956
|
+
version = rb_str_new2(mysql_get_client_info());
|
957
|
+
header_version = rb_str_new2(MYSQL_LINK_VERSION);
|
958
|
+
|
959
|
+
rb_enc_associate(version, rb_usascii_encoding());
|
960
|
+
rb_enc_associate(header_version, rb_usascii_encoding());
|
961
|
+
|
962
|
+
rb_hash_aset(version_info, sym_id, LONG2NUM(mysql_get_client_version()));
|
963
|
+
rb_hash_aset(version_info, sym_version, version);
|
964
|
+
rb_hash_aset(version_info, sym_header_version, header_version);
|
965
|
+
|
966
|
+
return version_info;
|
549
967
|
}
|
550
968
|
|
969
|
+
/* call-seq:
|
970
|
+
* client.server_info
|
971
|
+
*
|
972
|
+
* Returns a string that represents the server version number
|
973
|
+
*/
|
551
974
|
static VALUE rb_mysql_client_server_info(VALUE self) {
|
552
975
|
VALUE version, server_info;
|
553
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
554
976
|
rb_encoding *default_internal_enc;
|
555
977
|
rb_encoding *conn_enc;
|
556
|
-
#endif
|
557
978
|
GET_CLIENT(self);
|
558
979
|
|
559
|
-
|
560
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
980
|
+
REQUIRE_CONNECTED(wrapper);
|
561
981
|
default_internal_enc = rb_default_internal_encoding();
|
562
982
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
563
|
-
#endif
|
564
983
|
|
565
984
|
version = rb_hash_new();
|
566
985
|
rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
|
567
986
|
server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
|
568
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
569
987
|
rb_enc_associate(server_info, conn_enc);
|
570
988
|
if (default_internal_enc) {
|
571
989
|
server_info = rb_str_export_to_enc(server_info, default_internal_enc);
|
572
990
|
}
|
573
|
-
#endif
|
574
991
|
rb_hash_aset(version, sym_version, server_info);
|
575
992
|
return version;
|
576
993
|
}
|
577
994
|
|
995
|
+
/* call-seq:
|
996
|
+
* client.socket
|
997
|
+
*
|
998
|
+
* Return the file descriptor number for this client.
|
999
|
+
*/
|
1000
|
+
#ifndef _WIN32
|
578
1001
|
static VALUE rb_mysql_client_socket(VALUE self) {
|
579
1002
|
GET_CLIENT(self);
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
return INT2NUM(fd_set_fd);
|
1003
|
+
REQUIRE_CONNECTED(wrapper);
|
1004
|
+
return INT2NUM(wrapper->client->net.fd);
|
1005
|
+
}
|
584
1006
|
#else
|
1007
|
+
static VALUE rb_mysql_client_socket(RB_MYSQL_UNUSED VALUE self) {
|
585
1008
|
rb_raise(cMysql2Error, "Raw access to the mysql file descriptor isn't supported on Windows");
|
586
|
-
#endif
|
587
1009
|
}
|
1010
|
+
#endif
|
588
1011
|
|
1012
|
+
/* call-seq:
|
1013
|
+
* client.last_id
|
1014
|
+
*
|
1015
|
+
* Returns the value generated for an AUTO_INCREMENT column by the previous INSERT or UPDATE
|
1016
|
+
* statement.
|
1017
|
+
*/
|
589
1018
|
static VALUE rb_mysql_client_last_id(VALUE self) {
|
590
1019
|
GET_CLIENT(self);
|
591
|
-
|
1020
|
+
REQUIRE_CONNECTED(wrapper);
|
592
1021
|
return ULL2NUM(mysql_insert_id(wrapper->client));
|
593
1022
|
}
|
594
1023
|
|
1024
|
+
/* call-seq:
|
1025
|
+
* client.affected_rows
|
1026
|
+
*
|
1027
|
+
* returns the number of rows changed, deleted, or inserted by the last statement
|
1028
|
+
* if it was an UPDATE, DELETE, or INSERT.
|
1029
|
+
*/
|
595
1030
|
static VALUE rb_mysql_client_affected_rows(VALUE self) {
|
596
1031
|
my_ulonglong retVal;
|
597
1032
|
GET_CLIENT(self);
|
598
1033
|
|
599
|
-
|
1034
|
+
REQUIRE_CONNECTED(wrapper);
|
600
1035
|
retVal = mysql_affected_rows(wrapper->client);
|
601
1036
|
if (retVal == (my_ulonglong)-1) {
|
602
1037
|
rb_raise_mysql2_error(wrapper);
|
@@ -604,92 +1039,270 @@ static VALUE rb_mysql_client_affected_rows(VALUE self) {
|
|
604
1039
|
return ULL2NUM(retVal);
|
605
1040
|
}
|
606
1041
|
|
1042
|
+
/* call-seq:
|
1043
|
+
* client.thread_id
|
1044
|
+
*
|
1045
|
+
* Returns the thread ID of the current connection.
|
1046
|
+
*/
|
607
1047
|
static VALUE rb_mysql_client_thread_id(VALUE self) {
|
608
1048
|
unsigned long retVal;
|
609
1049
|
GET_CLIENT(self);
|
610
1050
|
|
611
|
-
|
1051
|
+
REQUIRE_CONNECTED(wrapper);
|
612
1052
|
retVal = mysql_thread_id(wrapper->client);
|
613
1053
|
return ULL2NUM(retVal);
|
614
1054
|
}
|
615
1055
|
|
616
|
-
static
|
1056
|
+
static void *nogvl_select_db(void *ptr) {
|
1057
|
+
struct nogvl_select_db_args *args = ptr;
|
1058
|
+
|
1059
|
+
if (mysql_select_db(args->mysql, args->db) == 0)
|
1060
|
+
return (void *)Qtrue;
|
1061
|
+
else
|
1062
|
+
return (void *)Qfalse;
|
1063
|
+
}
|
1064
|
+
|
1065
|
+
/* call-seq:
|
1066
|
+
* client.select_db(name)
|
1067
|
+
*
|
1068
|
+
* Causes the database specified by +name+ to become the default (current)
|
1069
|
+
* database on the connection specified by mysql.
|
1070
|
+
*/
|
1071
|
+
static VALUE rb_mysql_client_select_db(VALUE self, VALUE db)
|
1072
|
+
{
|
1073
|
+
struct nogvl_select_db_args args;
|
1074
|
+
|
1075
|
+
GET_CLIENT(self);
|
1076
|
+
REQUIRE_CONNECTED(wrapper);
|
1077
|
+
|
1078
|
+
args.mysql = wrapper->client;
|
1079
|
+
args.db = StringValueCStr(db);
|
1080
|
+
|
1081
|
+
if (rb_thread_call_without_gvl(nogvl_select_db, &args, RUBY_UBF_IO, 0) == Qfalse)
|
1082
|
+
rb_raise_mysql2_error(wrapper);
|
1083
|
+
|
1084
|
+
return db;
|
1085
|
+
}
|
1086
|
+
|
1087
|
+
static void *nogvl_ping(void *ptr) {
|
617
1088
|
MYSQL *client = ptr;
|
618
1089
|
|
619
|
-
return mysql_ping(client) == 0 ? Qtrue : Qfalse;
|
1090
|
+
return (void *)(mysql_ping(client) == 0 ? Qtrue : Qfalse);
|
620
1091
|
}
|
621
1092
|
|
1093
|
+
/* call-seq:
|
1094
|
+
* client.ping
|
1095
|
+
*
|
1096
|
+
* Checks whether the connection to the server is working. If the connection
|
1097
|
+
* has gone down and auto-reconnect is enabled an attempt to reconnect is made.
|
1098
|
+
* If the connection is down and auto-reconnect is disabled, ping returns an
|
1099
|
+
* error.
|
1100
|
+
*/
|
622
1101
|
static VALUE rb_mysql_client_ping(VALUE self) {
|
623
1102
|
GET_CLIENT(self);
|
624
1103
|
|
625
|
-
if (wrapper
|
1104
|
+
if (!CONNECTED(wrapper)) {
|
626
1105
|
return Qfalse;
|
627
1106
|
} else {
|
628
|
-
return
|
1107
|
+
return (VALUE)rb_thread_call_without_gvl(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
|
629
1108
|
}
|
630
1109
|
}
|
631
1110
|
|
632
|
-
|
633
|
-
|
1111
|
+
/* call-seq:
|
1112
|
+
* client.set_server_option(value)
|
1113
|
+
*
|
1114
|
+
* Enables or disables an option for the connection.
|
1115
|
+
* Read https://dev.mysql.com/doc/refman/5.7/en/mysql-set-server-option.html
|
1116
|
+
* for more information.
|
1117
|
+
*/
|
1118
|
+
static VALUE rb_mysql_client_set_server_option(VALUE self, VALUE value) {
|
634
1119
|
GET_CLIENT(self);
|
635
|
-
|
1120
|
+
|
1121
|
+
if (mysql_set_server_option(wrapper->client, NUM2INT(value)) == 0) {
|
1122
|
+
return Qtrue;
|
1123
|
+
} else {
|
1124
|
+
return Qfalse;
|
1125
|
+
}
|
636
1126
|
}
|
637
|
-
#endif
|
638
1127
|
|
639
|
-
|
640
|
-
|
1128
|
+
/* call-seq:
|
1129
|
+
* client.more_results?
|
1130
|
+
*
|
1131
|
+
* Returns true or false if there are more results to process.
|
1132
|
+
*/
|
1133
|
+
static VALUE rb_mysql_client_more_results(VALUE self)
|
1134
|
+
{
|
1135
|
+
GET_CLIENT(self);
|
1136
|
+
if (mysql_more_results(wrapper->client) == 0)
|
1137
|
+
return Qfalse;
|
1138
|
+
else
|
1139
|
+
return Qtrue;
|
1140
|
+
}
|
1141
|
+
|
1142
|
+
/* call-seq:
|
1143
|
+
* client.next_result
|
1144
|
+
*
|
1145
|
+
* Fetch the next result set from the server.
|
1146
|
+
* Returns nothing.
|
1147
|
+
*/
|
1148
|
+
static VALUE rb_mysql_client_next_result(VALUE self)
|
1149
|
+
{
|
1150
|
+
int ret;
|
1151
|
+
GET_CLIENT(self);
|
1152
|
+
ret = mysql_next_result(wrapper->client);
|
1153
|
+
if (ret > 0) {
|
1154
|
+
rb_raise_mysql2_error(wrapper);
|
1155
|
+
return Qfalse;
|
1156
|
+
} else if (ret == 0) {
|
1157
|
+
return Qtrue;
|
1158
|
+
} else {
|
1159
|
+
return Qfalse;
|
1160
|
+
}
|
1161
|
+
}
|
1162
|
+
|
1163
|
+
/* call-seq:
|
1164
|
+
* client.store_result
|
1165
|
+
*
|
1166
|
+
* Return the next result object from a query which
|
1167
|
+
* yielded multiple result sets.
|
1168
|
+
*/
|
1169
|
+
static VALUE rb_mysql_client_store_result(VALUE self)
|
1170
|
+
{
|
1171
|
+
MYSQL_RES * result;
|
1172
|
+
VALUE resultObj;
|
1173
|
+
VALUE current;
|
641
1174
|
GET_CLIENT(self);
|
642
1175
|
|
643
|
-
|
644
|
-
reconnect = value == Qfalse ? 0 : 1;
|
1176
|
+
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
|
645
1177
|
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
/* TODO: warning - unable to set reconnect behavior */
|
650
|
-
rb_warn("%s\n", mysql_error(wrapper->client));
|
1178
|
+
if (result == NULL) {
|
1179
|
+
if (mysql_errno(wrapper->client) != 0) {
|
1180
|
+
rb_raise_mysql2_error(wrapper);
|
651
1181
|
}
|
1182
|
+
/* no data and no error, so query was not a SELECT */
|
1183
|
+
return Qnil;
|
652
1184
|
}
|
653
|
-
|
1185
|
+
|
1186
|
+
// Duplicate the options hash and put the copy in the Result object
|
1187
|
+
current = rb_hash_dup(rb_ivar_get(self, intern_current_query_options));
|
1188
|
+
(void)RB_GC_GUARD(current);
|
1189
|
+
Check_Type(current, T_HASH);
|
1190
|
+
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil);
|
1191
|
+
|
1192
|
+
return resultObj;
|
654
1193
|
}
|
655
1194
|
|
656
|
-
|
657
|
-
|
1195
|
+
/* call-seq:
|
1196
|
+
* client.encoding
|
1197
|
+
*
|
1198
|
+
* Returns the encoding set on the client.
|
1199
|
+
*/
|
1200
|
+
static VALUE rb_mysql_client_encoding(VALUE self) {
|
658
1201
|
GET_CLIENT(self);
|
1202
|
+
return wrapper->encoding;
|
1203
|
+
}
|
659
1204
|
|
660
|
-
|
661
|
-
|
662
|
-
|
1205
|
+
/* call-seq:
|
1206
|
+
* client.automatic_close?
|
1207
|
+
*
|
1208
|
+
* @return [Boolean]
|
1209
|
+
*/
|
1210
|
+
static VALUE get_automatic_close(VALUE self) {
|
1211
|
+
GET_CLIENT(self);
|
1212
|
+
return wrapper->automatic_close ? Qtrue : Qfalse;
|
1213
|
+
}
|
663
1214
|
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
1215
|
+
/* call-seq:
|
1216
|
+
* client.automatic_close = false
|
1217
|
+
*
|
1218
|
+
* Set this to +false+ to leave the connection open after it is garbage
|
1219
|
+
* collected. To avoid "Aborted connection" errors on the server, explicitly
|
1220
|
+
* call +close+ when the connection is no longer needed.
|
1221
|
+
*
|
1222
|
+
* @see http://dev.mysql.com/doc/en/communication-errors.html
|
1223
|
+
*/
|
1224
|
+
static VALUE set_automatic_close(VALUE self, VALUE value) {
|
1225
|
+
GET_CLIENT(self);
|
1226
|
+
if (RTEST(value)) {
|
1227
|
+
wrapper->automatic_close = 1;
|
1228
|
+
} else {
|
1229
|
+
#ifndef _WIN32
|
1230
|
+
wrapper->automatic_close = 0;
|
1231
|
+
#else
|
1232
|
+
rb_warn("Connections are always closed by garbage collector on Windows");
|
1233
|
+
#endif
|
669
1234
|
}
|
670
1235
|
return value;
|
671
1236
|
}
|
672
1237
|
|
1238
|
+
/* call-seq:
|
1239
|
+
* client.reconnect = true
|
1240
|
+
*
|
1241
|
+
* Enable or disable the automatic reconnect behavior of libmysql.
|
1242
|
+
* Read http://dev.mysql.com/doc/refman/5.5/en/auto-reconnect.html
|
1243
|
+
* for more information.
|
1244
|
+
*/
|
1245
|
+
static VALUE set_reconnect(VALUE self, VALUE value) {
|
1246
|
+
return _mysql_client_options(self, MYSQL_OPT_RECONNECT, value);
|
1247
|
+
}
|
1248
|
+
|
1249
|
+
static VALUE set_local_infile(VALUE self, VALUE value) {
|
1250
|
+
return _mysql_client_options(self, MYSQL_OPT_LOCAL_INFILE, value);
|
1251
|
+
}
|
1252
|
+
|
1253
|
+
static VALUE set_connect_timeout(VALUE self, VALUE value) {
|
1254
|
+
long int sec;
|
1255
|
+
Check_Type(value, T_FIXNUM);
|
1256
|
+
sec = FIX2INT(value);
|
1257
|
+
if (sec < 0) {
|
1258
|
+
rb_raise(cMysql2Error, "connect_timeout must be a positive integer, you passed %ld", sec);
|
1259
|
+
}
|
1260
|
+
return _mysql_client_options(self, MYSQL_OPT_CONNECT_TIMEOUT, value);
|
1261
|
+
}
|
1262
|
+
|
1263
|
+
static VALUE set_read_timeout(VALUE self, VALUE value) {
|
1264
|
+
long int sec;
|
1265
|
+
Check_Type(value, T_FIXNUM);
|
1266
|
+
sec = FIX2INT(value);
|
1267
|
+
if (sec < 0) {
|
1268
|
+
rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
|
1269
|
+
}
|
1270
|
+
/* Set the instance variable here even though _mysql_client_options
|
1271
|
+
might not succeed, because the timeout is used in other ways
|
1272
|
+
elsewhere */
|
1273
|
+
rb_ivar_set(self, intern_read_timeout, value);
|
1274
|
+
return _mysql_client_options(self, MYSQL_OPT_READ_TIMEOUT, value);
|
1275
|
+
}
|
1276
|
+
|
1277
|
+
static VALUE set_write_timeout(VALUE self, VALUE value) {
|
1278
|
+
long int sec;
|
1279
|
+
Check_Type(value, T_FIXNUM);
|
1280
|
+
sec = FIX2INT(value);
|
1281
|
+
if (sec < 0) {
|
1282
|
+
rb_raise(cMysql2Error, "write_timeout must be a positive integer, you passed %ld", sec);
|
1283
|
+
}
|
1284
|
+
return _mysql_client_options(self, MYSQL_OPT_WRITE_TIMEOUT, value);
|
1285
|
+
}
|
1286
|
+
|
673
1287
|
static VALUE set_charset_name(VALUE self, VALUE value) {
|
674
|
-
char *
|
675
|
-
|
676
|
-
|
677
|
-
|
1288
|
+
char *charset_name;
|
1289
|
+
const struct mysql2_mysql_enc_name_to_rb_map *mysql2rb;
|
1290
|
+
rb_encoding *enc;
|
1291
|
+
VALUE rb_enc;
|
678
1292
|
GET_CLIENT(self);
|
679
1293
|
|
680
|
-
|
681
|
-
|
682
|
-
|
1294
|
+
Check_Type(value, T_STRING);
|
1295
|
+
charset_name = RSTRING_PTR(value);
|
1296
|
+
|
1297
|
+
mysql2rb = mysql2_mysql_enc_name_to_rb(charset_name, (unsigned int)RSTRING_LEN(value));
|
1298
|
+
if (mysql2rb == NULL || mysql2rb->rb_name == NULL) {
|
683
1299
|
VALUE inspect = rb_inspect(value);
|
684
1300
|
rb_raise(cMysql2Error, "Unsupported charset: '%s'", RSTRING_PTR(inspect));
|
685
1301
|
} else {
|
686
|
-
|
687
|
-
|
688
|
-
|
1302
|
+
enc = rb_enc_find(mysql2rb->rb_name);
|
1303
|
+
rb_enc = rb_enc_from_encoding(enc);
|
1304
|
+
wrapper->encoding = rb_enc;
|
689
1305
|
}
|
690
|
-
#endif
|
691
|
-
|
692
|
-
charset_name = StringValuePtr(value);
|
693
1306
|
|
694
1307
|
if (mysql_options(wrapper->client, MYSQL_SET_CHARSET_NAME, charset_name)) {
|
695
1308
|
/* TODO: warning - unable to set charset */
|
@@ -702,192 +1315,354 @@ static VALUE set_charset_name(VALUE self, VALUE value) {
|
|
702
1315
|
static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE capath, VALUE cipher) {
|
703
1316
|
GET_CLIENT(self);
|
704
1317
|
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
NIL_P(cipher) ? NULL : StringValuePtr(cipher));
|
712
|
-
}
|
1318
|
+
mysql_ssl_set(wrapper->client,
|
1319
|
+
NIL_P(key) ? NULL : StringValueCStr(key),
|
1320
|
+
NIL_P(cert) ? NULL : StringValueCStr(cert),
|
1321
|
+
NIL_P(ca) ? NULL : StringValueCStr(ca),
|
1322
|
+
NIL_P(capath) ? NULL : StringValueCStr(capath),
|
1323
|
+
NIL_P(cipher) ? NULL : StringValueCStr(cipher));
|
713
1324
|
|
714
1325
|
return self;
|
715
1326
|
}
|
716
1327
|
|
717
|
-
static VALUE
|
1328
|
+
static VALUE set_secure_auth(VALUE self, VALUE value) {
|
1329
|
+
/* This option was deprecated in MySQL 5.x and removed in MySQL 8.0 */
|
1330
|
+
#ifdef MYSQL_SECURE_AUTH
|
1331
|
+
return _mysql_client_options(self, MYSQL_SECURE_AUTH, value);
|
1332
|
+
#else
|
1333
|
+
return Qfalse;
|
1334
|
+
#endif
|
1335
|
+
}
|
1336
|
+
|
1337
|
+
static VALUE set_read_default_file(VALUE self, VALUE value) {
|
1338
|
+
return _mysql_client_options(self, MYSQL_READ_DEFAULT_FILE, value);
|
1339
|
+
}
|
1340
|
+
|
1341
|
+
static VALUE set_read_default_group(VALUE self, VALUE value) {
|
1342
|
+
return _mysql_client_options(self, MYSQL_READ_DEFAULT_GROUP, value);
|
1343
|
+
}
|
1344
|
+
|
1345
|
+
static VALUE set_init_command(VALUE self, VALUE value) {
|
1346
|
+
return _mysql_client_options(self, MYSQL_INIT_COMMAND, value);
|
1347
|
+
}
|
1348
|
+
|
1349
|
+
static VALUE set_default_auth(VALUE self, VALUE value) {
|
1350
|
+
return _mysql_client_options(self, MYSQL_DEFAULT_AUTH, value);
|
1351
|
+
}
|
1352
|
+
|
1353
|
+
static VALUE set_enable_cleartext_plugin(VALUE self, VALUE value) {
|
1354
|
+
#ifdef HAVE_CONST_MYSQL_ENABLE_CLEARTEXT_PLUGIN
|
1355
|
+
return _mysql_client_options(self, MYSQL_ENABLE_CLEARTEXT_PLUGIN, value);
|
1356
|
+
#else
|
1357
|
+
rb_raise(cMysql2Error, "enable-cleartext-plugin is not available, you may need a newer MySQL client library");
|
1358
|
+
#endif
|
1359
|
+
}
|
1360
|
+
|
1361
|
+
static VALUE initialize_ext(VALUE self) {
|
718
1362
|
GET_CLIENT(self);
|
719
1363
|
|
720
|
-
if (
|
1364
|
+
if ((VALUE)rb_thread_call_without_gvl(nogvl_init, wrapper, RUBY_UBF_IO, 0) == Qfalse) {
|
721
1365
|
/* TODO: warning - not enough memory? */
|
722
|
-
|
1366
|
+
rb_raise_mysql2_error(wrapper);
|
723
1367
|
}
|
724
1368
|
|
725
|
-
wrapper->
|
1369
|
+
wrapper->initialized = 1;
|
726
1370
|
return self;
|
727
1371
|
}
|
728
1372
|
|
1373
|
+
/* call-seq: client.prepare # => Mysql2::Statement
|
1374
|
+
*
|
1375
|
+
* Create a new prepared statement.
|
1376
|
+
*/
|
1377
|
+
static VALUE rb_mysql_client_prepare_statement(VALUE self, VALUE sql) {
|
1378
|
+
GET_CLIENT(self);
|
1379
|
+
REQUIRE_CONNECTED(wrapper);
|
1380
|
+
|
1381
|
+
return rb_mysql_stmt_new(self, sql);
|
1382
|
+
}
|
1383
|
+
|
729
1384
|
void init_mysql2_client() {
|
730
|
-
|
731
|
-
|
1385
|
+
#ifdef _WIN32
|
1386
|
+
/* verify the libmysql we're about to use was the version we were built against
|
1387
|
+
https://github.com/luislavena/mysql-gem/commit/a600a9c459597da0712f70f43736e24b484f8a99 */
|
732
1388
|
int i;
|
733
1389
|
int dots = 0;
|
734
1390
|
const char *lib = mysql_get_client_info();
|
735
|
-
|
1391
|
+
|
1392
|
+
for (i = 0; lib[i] != 0 && MYSQL_LINK_VERSION[i] != 0; i++) {
|
736
1393
|
if (lib[i] == '.') {
|
737
1394
|
dots++;
|
738
|
-
|
1395
|
+
/* we only compare MAJOR and MINOR */
|
739
1396
|
if (dots == 2) break;
|
740
1397
|
}
|
741
|
-
if (lib[i] !=
|
742
|
-
rb_raise(rb_eRuntimeError, "Incorrect MySQL client library version! This gem was compiled for %s but the client library is %s.",
|
743
|
-
return;
|
1398
|
+
if (lib[i] != MYSQL_LINK_VERSION[i]) {
|
1399
|
+
rb_raise(rb_eRuntimeError, "Incorrect MySQL client library version! This gem was compiled for %s but the client library is %s.", MYSQL_LINK_VERSION, lib);
|
744
1400
|
}
|
745
1401
|
}
|
1402
|
+
#endif
|
746
1403
|
|
1404
|
+
/* Initializing mysql library, so different threads could call Client.new */
|
1405
|
+
/* without race condition in the library */
|
1406
|
+
if (mysql_library_init(0, NULL, NULL) != 0) {
|
1407
|
+
rb_raise(rb_eRuntimeError, "Could not initialize MySQL client library");
|
1408
|
+
}
|
1409
|
+
|
1410
|
+
#if 0
|
1411
|
+
mMysql2 = rb_define_module("Mysql2"); Teach RDoc about Mysql2 constant.
|
1412
|
+
#endif
|
747
1413
|
cMysql2Client = rb_define_class_under(mMysql2, "Client", rb_cObject);
|
748
1414
|
|
749
1415
|
rb_define_alloc_func(cMysql2Client, allocate);
|
750
1416
|
|
751
1417
|
rb_define_singleton_method(cMysql2Client, "escape", rb_mysql_client_escape, 1);
|
1418
|
+
rb_define_singleton_method(cMysql2Client, "info", rb_mysql_client_info, 0);
|
752
1419
|
|
753
1420
|
rb_define_method(cMysql2Client, "close", rb_mysql_client_close, 0);
|
754
|
-
rb_define_method(cMysql2Client, "
|
1421
|
+
rb_define_method(cMysql2Client, "closed?", rb_mysql_client_closed, 0);
|
1422
|
+
rb_define_method(cMysql2Client, "abandon_results!", rb_mysql_client_abandon_results, 0);
|
755
1423
|
rb_define_method(cMysql2Client, "escape", rb_mysql_client_real_escape, 1);
|
756
|
-
rb_define_method(cMysql2Client, "info", rb_mysql_client_info, 0);
|
757
1424
|
rb_define_method(cMysql2Client, "server_info", rb_mysql_client_server_info, 0);
|
758
1425
|
rb_define_method(cMysql2Client, "socket", rb_mysql_client_socket, 0);
|
759
1426
|
rb_define_method(cMysql2Client, "async_result", rb_mysql_client_async_result, 0);
|
760
1427
|
rb_define_method(cMysql2Client, "last_id", rb_mysql_client_last_id, 0);
|
761
1428
|
rb_define_method(cMysql2Client, "affected_rows", rb_mysql_client_affected_rows, 0);
|
1429
|
+
rb_define_method(cMysql2Client, "prepare", rb_mysql_client_prepare_statement, 1);
|
762
1430
|
rb_define_method(cMysql2Client, "thread_id", rb_mysql_client_thread_id, 0);
|
763
1431
|
rb_define_method(cMysql2Client, "ping", rb_mysql_client_ping, 0);
|
764
|
-
|
1432
|
+
rb_define_method(cMysql2Client, "select_db", rb_mysql_client_select_db, 1);
|
1433
|
+
rb_define_method(cMysql2Client, "set_server_option", rb_mysql_client_set_server_option, 1);
|
1434
|
+
rb_define_method(cMysql2Client, "more_results?", rb_mysql_client_more_results, 0);
|
1435
|
+
rb_define_method(cMysql2Client, "next_result", rb_mysql_client_next_result, 0);
|
1436
|
+
rb_define_method(cMysql2Client, "store_result", rb_mysql_client_store_result, 0);
|
1437
|
+
rb_define_method(cMysql2Client, "automatic_close?", get_automatic_close, 0);
|
1438
|
+
rb_define_method(cMysql2Client, "automatic_close=", set_automatic_close, 1);
|
1439
|
+
rb_define_method(cMysql2Client, "reconnect=", set_reconnect, 1);
|
1440
|
+
rb_define_method(cMysql2Client, "warning_count", rb_mysql_client_warning_count, 0);
|
1441
|
+
rb_define_method(cMysql2Client, "query_info_string", rb_mysql_info, 0);
|
1442
|
+
rb_define_method(cMysql2Client, "ssl_cipher", rb_mysql_get_ssl_cipher, 0);
|
765
1443
|
rb_define_method(cMysql2Client, "encoding", rb_mysql_client_encoding, 0);
|
766
|
-
#endif
|
767
1444
|
|
768
|
-
rb_define_private_method(cMysql2Client, "reconnect=", set_reconnect, 1);
|
769
1445
|
rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
|
1446
|
+
rb_define_private_method(cMysql2Client, "read_timeout=", set_read_timeout, 1);
|
1447
|
+
rb_define_private_method(cMysql2Client, "write_timeout=", set_write_timeout, 1);
|
1448
|
+
rb_define_private_method(cMysql2Client, "local_infile=", set_local_infile, 1);
|
770
1449
|
rb_define_private_method(cMysql2Client, "charset_name=", set_charset_name, 1);
|
1450
|
+
rb_define_private_method(cMysql2Client, "secure_auth=", set_secure_auth, 1);
|
1451
|
+
rb_define_private_method(cMysql2Client, "default_file=", set_read_default_file, 1);
|
1452
|
+
rb_define_private_method(cMysql2Client, "default_group=", set_read_default_group, 1);
|
1453
|
+
rb_define_private_method(cMysql2Client, "init_command=", set_init_command, 1);
|
1454
|
+
rb_define_private_method(cMysql2Client, "default_auth=", set_default_auth, 1);
|
771
1455
|
rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
|
772
|
-
rb_define_private_method(cMysql2Client, "
|
773
|
-
rb_define_private_method(cMysql2Client, "
|
774
|
-
|
775
|
-
|
1456
|
+
rb_define_private_method(cMysql2Client, "ssl_mode=", rb_set_ssl_mode_option, 1);
|
1457
|
+
rb_define_private_method(cMysql2Client, "enable_cleartext_plugin=", set_enable_cleartext_plugin, 1);
|
1458
|
+
rb_define_private_method(cMysql2Client, "initialize_ext", initialize_ext, 0);
|
1459
|
+
rb_define_private_method(cMysql2Client, "connect", rb_mysql_connect, 8);
|
1460
|
+
rb_define_private_method(cMysql2Client, "_query", rb_mysql_query, 2);
|
776
1461
|
|
777
1462
|
sym_id = ID2SYM(rb_intern("id"));
|
778
1463
|
sym_version = ID2SYM(rb_intern("version"));
|
1464
|
+
sym_header_version = ID2SYM(rb_intern("header_version"));
|
779
1465
|
sym_async = ID2SYM(rb_intern("async"));
|
780
1466
|
sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
|
781
1467
|
sym_as = ID2SYM(rb_intern("as"));
|
782
1468
|
sym_array = ID2SYM(rb_intern("array"));
|
1469
|
+
sym_stream = ID2SYM(rb_intern("stream"));
|
1470
|
+
|
1471
|
+
sym_no_good_index_used = ID2SYM(rb_intern("no_good_index_used"));
|
1472
|
+
sym_no_index_used = ID2SYM(rb_intern("no_index_used"));
|
1473
|
+
sym_query_was_slow = ID2SYM(rb_intern("query_was_slow"));
|
783
1474
|
|
1475
|
+
intern_brackets = rb_intern("[]");
|
784
1476
|
intern_merge = rb_intern("merge");
|
785
|
-
|
786
|
-
|
1477
|
+
intern_merge_bang = rb_intern("merge!");
|
1478
|
+
intern_new_with_args = rb_intern("new_with_args");
|
1479
|
+
intern_current_query_options = rb_intern("@current_query_options");
|
1480
|
+
intern_read_timeout = rb_intern("@read_timeout");
|
787
1481
|
|
788
1482
|
#ifdef CLIENT_LONG_PASSWORD
|
789
1483
|
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
|
790
|
-
|
1484
|
+
LONG2NUM(CLIENT_LONG_PASSWORD));
|
1485
|
+
#else
|
1486
|
+
/* HACK because MariaDB 10.2 no longer defines this constant,
|
1487
|
+
* but we're using it in our default connection flags. */
|
1488
|
+
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"), INT2NUM(0));
|
791
1489
|
#endif
|
792
1490
|
|
793
1491
|
#ifdef CLIENT_FOUND_ROWS
|
794
1492
|
rb_const_set(cMysql2Client, rb_intern("FOUND_ROWS"),
|
795
|
-
|
1493
|
+
LONG2NUM(CLIENT_FOUND_ROWS));
|
796
1494
|
#endif
|
797
1495
|
|
798
1496
|
#ifdef CLIENT_LONG_FLAG
|
799
1497
|
rb_const_set(cMysql2Client, rb_intern("LONG_FLAG"),
|
800
|
-
|
1498
|
+
LONG2NUM(CLIENT_LONG_FLAG));
|
801
1499
|
#endif
|
802
1500
|
|
803
1501
|
#ifdef CLIENT_CONNECT_WITH_DB
|
804
1502
|
rb_const_set(cMysql2Client, rb_intern("CONNECT_WITH_DB"),
|
805
|
-
|
1503
|
+
LONG2NUM(CLIENT_CONNECT_WITH_DB));
|
806
1504
|
#endif
|
807
1505
|
|
808
1506
|
#ifdef CLIENT_NO_SCHEMA
|
809
1507
|
rb_const_set(cMysql2Client, rb_intern("NO_SCHEMA"),
|
810
|
-
|
1508
|
+
LONG2NUM(CLIENT_NO_SCHEMA));
|
811
1509
|
#endif
|
812
1510
|
|
813
1511
|
#ifdef CLIENT_COMPRESS
|
814
|
-
rb_const_set(cMysql2Client, rb_intern("COMPRESS"),
|
1512
|
+
rb_const_set(cMysql2Client, rb_intern("COMPRESS"), LONG2NUM(CLIENT_COMPRESS));
|
815
1513
|
#endif
|
816
1514
|
|
817
1515
|
#ifdef CLIENT_ODBC
|
818
|
-
rb_const_set(cMysql2Client, rb_intern("ODBC"),
|
1516
|
+
rb_const_set(cMysql2Client, rb_intern("ODBC"), LONG2NUM(CLIENT_ODBC));
|
819
1517
|
#endif
|
820
1518
|
|
821
1519
|
#ifdef CLIENT_LOCAL_FILES
|
822
1520
|
rb_const_set(cMysql2Client, rb_intern("LOCAL_FILES"),
|
823
|
-
|
1521
|
+
LONG2NUM(CLIENT_LOCAL_FILES));
|
824
1522
|
#endif
|
825
1523
|
|
826
1524
|
#ifdef CLIENT_IGNORE_SPACE
|
827
1525
|
rb_const_set(cMysql2Client, rb_intern("IGNORE_SPACE"),
|
828
|
-
|
1526
|
+
LONG2NUM(CLIENT_IGNORE_SPACE));
|
829
1527
|
#endif
|
830
1528
|
|
831
1529
|
#ifdef CLIENT_PROTOCOL_41
|
832
1530
|
rb_const_set(cMysql2Client, rb_intern("PROTOCOL_41"),
|
833
|
-
|
1531
|
+
LONG2NUM(CLIENT_PROTOCOL_41));
|
834
1532
|
#endif
|
835
1533
|
|
836
1534
|
#ifdef CLIENT_INTERACTIVE
|
837
1535
|
rb_const_set(cMysql2Client, rb_intern("INTERACTIVE"),
|
838
|
-
|
1536
|
+
LONG2NUM(CLIENT_INTERACTIVE));
|
839
1537
|
#endif
|
840
1538
|
|
841
1539
|
#ifdef CLIENT_SSL
|
842
|
-
rb_const_set(cMysql2Client, rb_intern("SSL"),
|
1540
|
+
rb_const_set(cMysql2Client, rb_intern("SSL"), LONG2NUM(CLIENT_SSL));
|
843
1541
|
#endif
|
844
1542
|
|
845
1543
|
#ifdef CLIENT_IGNORE_SIGPIPE
|
846
1544
|
rb_const_set(cMysql2Client, rb_intern("IGNORE_SIGPIPE"),
|
847
|
-
|
1545
|
+
LONG2NUM(CLIENT_IGNORE_SIGPIPE));
|
848
1546
|
#endif
|
849
1547
|
|
850
1548
|
#ifdef CLIENT_TRANSACTIONS
|
851
1549
|
rb_const_set(cMysql2Client, rb_intern("TRANSACTIONS"),
|
852
|
-
|
1550
|
+
LONG2NUM(CLIENT_TRANSACTIONS));
|
853
1551
|
#endif
|
854
1552
|
|
855
1553
|
#ifdef CLIENT_RESERVED
|
856
|
-
rb_const_set(cMysql2Client, rb_intern("RESERVED"),
|
1554
|
+
rb_const_set(cMysql2Client, rb_intern("RESERVED"), LONG2NUM(CLIENT_RESERVED));
|
857
1555
|
#endif
|
858
1556
|
|
859
1557
|
#ifdef CLIENT_SECURE_CONNECTION
|
860
1558
|
rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"),
|
861
|
-
|
1559
|
+
LONG2NUM(CLIENT_SECURE_CONNECTION));
|
1560
|
+
#else
|
1561
|
+
/* HACK because MySQL5.7 no longer defines this constant,
|
1562
|
+
* but we're using it in our default connection flags. */
|
1563
|
+
rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"), LONG2NUM(0));
|
1564
|
+
#endif
|
1565
|
+
|
1566
|
+
#ifdef HAVE_CONST_MYSQL_OPTION_MULTI_STATEMENTS_ON
|
1567
|
+
rb_const_set(cMysql2Client, rb_intern("OPTION_MULTI_STATEMENTS_ON"),
|
1568
|
+
LONG2NUM(MYSQL_OPTION_MULTI_STATEMENTS_ON));
|
1569
|
+
#endif
|
1570
|
+
|
1571
|
+
#ifdef HAVE_CONST_MYSQL_OPTION_MULTI_STATEMENTS_OFF
|
1572
|
+
rb_const_set(cMysql2Client, rb_intern("OPTION_MULTI_STATEMENTS_OFF"),
|
1573
|
+
LONG2NUM(MYSQL_OPTION_MULTI_STATEMENTS_OFF));
|
862
1574
|
#endif
|
863
1575
|
|
864
1576
|
#ifdef CLIENT_MULTI_STATEMENTS
|
865
1577
|
rb_const_set(cMysql2Client, rb_intern("MULTI_STATEMENTS"),
|
866
|
-
|
1578
|
+
LONG2NUM(CLIENT_MULTI_STATEMENTS));
|
867
1579
|
#endif
|
868
1580
|
|
869
1581
|
#ifdef CLIENT_PS_MULTI_RESULTS
|
870
1582
|
rb_const_set(cMysql2Client, rb_intern("PS_MULTI_RESULTS"),
|
871
|
-
|
1583
|
+
LONG2NUM(CLIENT_PS_MULTI_RESULTS));
|
872
1584
|
#endif
|
873
1585
|
|
874
1586
|
#ifdef CLIENT_SSL_VERIFY_SERVER_CERT
|
875
1587
|
rb_const_set(cMysql2Client, rb_intern("SSL_VERIFY_SERVER_CERT"),
|
876
|
-
|
1588
|
+
LONG2NUM(CLIENT_SSL_VERIFY_SERVER_CERT));
|
877
1589
|
#endif
|
878
1590
|
|
879
1591
|
#ifdef CLIENT_REMEMBER_OPTIONS
|
880
1592
|
rb_const_set(cMysql2Client, rb_intern("REMEMBER_OPTIONS"),
|
881
|
-
|
1593
|
+
LONG2NUM(CLIENT_REMEMBER_OPTIONS));
|
882
1594
|
#endif
|
883
1595
|
|
884
1596
|
#ifdef CLIENT_ALL_FLAGS
|
885
1597
|
rb_const_set(cMysql2Client, rb_intern("ALL_FLAGS"),
|
886
|
-
|
1598
|
+
LONG2NUM(CLIENT_ALL_FLAGS));
|
887
1599
|
#endif
|
888
1600
|
|
889
1601
|
#ifdef CLIENT_BASIC_FLAGS
|
890
1602
|
rb_const_set(cMysql2Client, rb_intern("BASIC_FLAGS"),
|
891
|
-
|
1603
|
+
LONG2NUM(CLIENT_BASIC_FLAGS));
|
1604
|
+
#endif
|
1605
|
+
|
1606
|
+
#ifdef CLIENT_CONNECT_ATTRS
|
1607
|
+
rb_const_set(cMysql2Client, rb_intern("CONNECT_ATTRS"),
|
1608
|
+
LONG2NUM(CLIENT_CONNECT_ATTRS));
|
1609
|
+
#else
|
1610
|
+
/* HACK because MySQL 5.5 and earlier don't define this constant,
|
1611
|
+
* but we're using it in our default connection flags. */
|
1612
|
+
rb_const_set(cMysql2Client, rb_intern("CONNECT_ATTRS"),
|
1613
|
+
INT2NUM(0));
|
1614
|
+
#endif
|
1615
|
+
|
1616
|
+
#if defined(FULL_SSL_MODE_SUPPORT) // MySQL 5.7.11 and above
|
1617
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
|
1618
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_PREFERRED"), INT2NUM(SSL_MODE_PREFERRED));
|
1619
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(SSL_MODE_REQUIRED));
|
1620
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_CA"), INT2NUM(SSL_MODE_VERIFY_CA));
|
1621
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(SSL_MODE_VERIFY_IDENTITY));
|
1622
|
+
#elif defined(HAVE_CONST_MYSQL_OPT_SSL_ENFORCE) // MySQL 5.7.3 - 5.7.10
|
1623
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
|
1624
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(SSL_MODE_REQUIRED));
|
1625
|
+
#endif
|
1626
|
+
|
1627
|
+
#ifndef HAVE_CONST_SSL_MODE_DISABLED
|
1628
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(0));
|
1629
|
+
#endif
|
1630
|
+
#ifndef HAVE_CONST_SSL_MODE_PREFERRED
|
1631
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_PREFERRED"), INT2NUM(0));
|
1632
|
+
#endif
|
1633
|
+
#ifndef HAVE_CONST_SSL_MODE_REQUIRED
|
1634
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(0));
|
1635
|
+
#endif
|
1636
|
+
#ifndef HAVE_CONST_SSL_MODE_VERIFY_CA
|
1637
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_CA"), INT2NUM(0));
|
1638
|
+
#endif
|
1639
|
+
#ifndef HAVE_CONST_SSL_MODE_VERIFY_IDENTITY
|
1640
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(0));
|
892
1641
|
#endif
|
893
1642
|
}
|
1643
|
+
|
1644
|
+
#define flag_to_bool(f) ((client->server_status & f) ? Qtrue : Qfalse)
|
1645
|
+
|
1646
|
+
void rb_mysql_set_server_query_flags(MYSQL *client, VALUE result) {
|
1647
|
+
VALUE server_flags = rb_hash_new();
|
1648
|
+
|
1649
|
+
#ifdef HAVE_CONST_SERVER_QUERY_NO_GOOD_INDEX_USED
|
1650
|
+
rb_hash_aset(server_flags, sym_no_good_index_used, flag_to_bool(SERVER_QUERY_NO_GOOD_INDEX_USED));
|
1651
|
+
#else
|
1652
|
+
rb_hash_aset(server_flags, sym_no_good_index_used, Qnil);
|
1653
|
+
#endif
|
1654
|
+
|
1655
|
+
#ifdef HAVE_CONST_SERVER_QUERY_NO_INDEX_USED
|
1656
|
+
rb_hash_aset(server_flags, sym_no_index_used, flag_to_bool(SERVER_QUERY_NO_INDEX_USED));
|
1657
|
+
#else
|
1658
|
+
rb_hash_aset(server_flags, sym_no_index_used, Qnil);
|
1659
|
+
#endif
|
1660
|
+
|
1661
|
+
#ifdef HAVE_CONST_SERVER_QUERY_WAS_SLOW
|
1662
|
+
rb_hash_aset(server_flags, sym_query_was_slow, flag_to_bool(SERVER_QUERY_WAS_SLOW));
|
1663
|
+
#else
|
1664
|
+
rb_hash_aset(server_flags, sym_query_was_slow, Qnil);
|
1665
|
+
#endif
|
1666
|
+
|
1667
|
+
rb_iv_set(result, "@server_flags", server_flags);
|
1668
|
+
}
|