mysql2 0.2.24 → 0.3.0
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.
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/CHANGELOG.md +148 -0
- data/Gemfile +3 -0
- data/README.rdoc +257 -0
- data/Rakefile +5 -0
- data/benchmark/active_record.rb +51 -0
- data/benchmark/active_record_threaded.rb +42 -0
- data/benchmark/allocations.rb +33 -0
- data/benchmark/escape.rb +36 -0
- data/benchmark/query_with_mysql_casting.rb +80 -0
- data/benchmark/query_without_mysql_casting.rb +47 -0
- data/benchmark/sequel.rb +37 -0
- data/benchmark/setup_db.rb +119 -0
- data/benchmark/threaded.rb +44 -0
- data/ext/mysql2/client.c +272 -849
- data/ext/mysql2/client.h +12 -27
- data/ext/mysql2/extconf.rb +14 -72
- data/ext/mysql2/mysql2_ext.h +4 -7
- data/ext/mysql2/result.c +123 -319
- data/ext/mysql2/result.h +1 -4
- data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +64 -0
- data/lib/active_record/fiber_patches.rb +104 -0
- data/lib/mysql2.rb +5 -20
- data/lib/mysql2/client.rb +200 -50
- data/lib/mysql2/em.rb +3 -13
- data/lib/mysql2/em_fiber.rb +31 -0
- data/lib/mysql2/error.rb +6 -71
- data/lib/mysql2/version.rb +2 -2
- data/mysql2.gemspec +32 -0
- data/spec/em/em_fiber_spec.rb +22 -0
- data/spec/em/em_spec.rb +9 -74
- data/spec/mysql2/client_spec.rb +126 -593
- data/spec/mysql2/error_spec.rb +44 -58
- data/spec/mysql2/result_spec.rb +85 -257
- data/spec/spec_helper.rb +3 -24
- data/tasks/benchmarks.rake +20 -0
- data/tasks/compile.rake +71 -0
- data/tasks/rspec.rake +16 -0
- data/tasks/vendor_mysql.rake +40 -0
- metadata +179 -92
- checksums.yaml +0 -7
- data/README.md +0 -524
- data/ext/mysql2/infile.c +0 -122
- data/ext/mysql2/infile.h +0 -1
- data/ext/mysql2/mysql_enc_name_to_ruby.h +0 -168
- data/ext/mysql2/mysql_enc_to_ruby.h +0 -246
- data/ext/mysql2/wait_for_single_fd.h +0 -36
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +0 -635
- data/lib/arel/engines/sql/compilers/mysql2_compiler.rb +0 -11
- data/lib/mysql2/console.rb +0 -5
- data/spec/configuration.yml.example +0 -17
- data/spec/my.cnf.example +0 -9
- data/spec/test_data +0 -1
- data/support/mysql_enc_to_ruby.rb +0 -82
- data/support/ruby_enc_to_mysql.rb +0 -61
data/ext/mysql2/client.c
CHANGED
@@ -1,68 +1,28 @@
|
|
1
1
|
#include <mysql2_ext.h>
|
2
|
-
|
3
|
-
#include <time.h>
|
2
|
+
#include <client.h>
|
4
3
|
#include <errno.h>
|
5
|
-
#ifndef _WIN32
|
6
|
-
#include <sys/types.h>
|
7
|
-
#include <sys/socket.h>
|
8
|
-
#endif
|
9
|
-
#ifndef _MSC_VER
|
10
|
-
#include <unistd.h>
|
11
|
-
#endif
|
12
|
-
#include <fcntl.h>
|
13
|
-
#include "wait_for_single_fd.h"
|
14
|
-
|
15
|
-
#include "mysql_enc_name_to_ruby.h"
|
16
4
|
|
17
5
|
VALUE cMysql2Client;
|
18
6
|
extern VALUE mMysql2, cMysql2Error;
|
19
|
-
static VALUE
|
20
|
-
static
|
7
|
+
static VALUE intern_encoding_from_charset;
|
8
|
+
static VALUE sym_id, sym_version, sym_async, sym_symbolize_keys, sym_as, sym_array;
|
9
|
+
static ID intern_merge, intern_error_number_eql, intern_sql_state_eql;
|
21
10
|
|
22
|
-
#
|
23
|
-
|
24
|
-
return rb_funcall(rb_cHash, rb_intern("[]"), 1, other);
|
25
|
-
}
|
26
|
-
#endif
|
27
|
-
|
28
|
-
#define REQUIRE_INITIALIZED(wrapper) \
|
29
|
-
if (!wrapper->initialized) { \
|
30
|
-
rb_raise(cMysql2Error, "MySQL client is not initialized"); \
|
31
|
-
}
|
32
|
-
|
33
|
-
#define REQUIRE_CONNECTED(wrapper) \
|
34
|
-
REQUIRE_INITIALIZED(wrapper) \
|
35
|
-
if (!wrapper->connected && !wrapper->reconnect_enabled) { \
|
11
|
+
#define REQUIRE_OPEN_DB(wrapper) \
|
12
|
+
if(wrapper->closed) { \
|
36
13
|
rb_raise(cMysql2Error, "closed MySQL connection"); \
|
37
14
|
}
|
38
15
|
|
39
|
-
#define REQUIRE_NOT_CONNECTED(wrapper) \
|
40
|
-
REQUIRE_INITIALIZED(wrapper) \
|
41
|
-
if (wrapper->connected) { \
|
42
|
-
rb_raise(cMysql2Error, "MySQL connection is already open"); \
|
43
|
-
}
|
44
|
-
|
45
16
|
#define MARK_CONN_INACTIVE(conn) \
|
46
|
-
wrapper->
|
17
|
+
wrapper->active = 0
|
47
18
|
|
48
19
|
#define GET_CLIENT(self) \
|
49
20
|
mysql_client_wrapper *wrapper; \
|
50
21
|
Data_Get_Struct(self, mysql_client_wrapper, wrapper)
|
51
22
|
|
52
|
-
/*
|
53
|
-
* compatability with mysql-connector-c, where LIBMYSQL_VERSION is the correct
|
54
|
-
* variable to use, but MYSQL_SERVER_VERSION gives the correct numbers when
|
55
|
-
* linking against the server itself
|
56
|
-
*/
|
57
|
-
#ifdef LIBMYSQL_VERSION
|
58
|
-
#define MYSQL_LINK_VERSION LIBMYSQL_VERSION
|
59
|
-
#else
|
60
|
-
#define MYSQL_LINK_VERSION MYSQL_SERVER_VERSION
|
61
|
-
#endif
|
62
|
-
|
63
23
|
/*
|
64
24
|
* used to pass all arguments to mysql_real_connect while inside
|
65
|
-
*
|
25
|
+
* rb_thread_blocking_region
|
66
26
|
*/
|
67
27
|
struct nogvl_connect_args {
|
68
28
|
MYSQL *mysql;
|
@@ -77,23 +37,11 @@ struct nogvl_connect_args {
|
|
77
37
|
|
78
38
|
/*
|
79
39
|
* used to pass all arguments to mysql_send_query while inside
|
80
|
-
*
|
40
|
+
* rb_thread_blocking_region
|
81
41
|
*/
|
82
42
|
struct nogvl_send_query_args {
|
83
43
|
MYSQL *mysql;
|
84
44
|
VALUE sql;
|
85
|
-
const char *sql_ptr;
|
86
|
-
long sql_len;
|
87
|
-
mysql_client_wrapper *wrapper;
|
88
|
-
};
|
89
|
-
|
90
|
-
/*
|
91
|
-
* used to pass all arguments to mysql_select_db while inside
|
92
|
-
* rb_thread_call_without_gvl
|
93
|
-
*/
|
94
|
-
struct nogvl_select_db_args {
|
95
|
-
MYSQL *mysql;
|
96
|
-
char *db;
|
97
45
|
};
|
98
46
|
|
99
47
|
/*
|
@@ -122,136 +70,94 @@ static void rb_mysql_client_mark(void * wrapper) {
|
|
122
70
|
mysql_client_wrapper * w = wrapper;
|
123
71
|
if (w) {
|
124
72
|
rb_gc_mark(w->encoding);
|
125
|
-
rb_gc_mark(w->active_thread);
|
126
73
|
}
|
127
74
|
}
|
128
75
|
|
129
76
|
static VALUE rb_raise_mysql2_error(mysql_client_wrapper *wrapper) {
|
130
77
|
VALUE rb_error_msg = rb_str_new2(mysql_error(wrapper->client));
|
131
78
|
VALUE rb_sql_state = rb_tainted_str_new2(mysql_sqlstate(wrapper->client));
|
132
|
-
VALUE e;
|
133
|
-
|
134
79
|
#ifdef HAVE_RUBY_ENCODING_H
|
135
|
-
|
136
|
-
|
80
|
+
rb_encoding *default_internal_enc = rb_default_internal_encoding();
|
81
|
+
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
|
82
|
+
|
83
|
+
rb_enc_associate(rb_error_msg, conn_enc);
|
84
|
+
rb_enc_associate(rb_sql_state, conn_enc);
|
85
|
+
if (default_internal_enc) {
|
86
|
+
rb_error_msg = rb_str_export_to_enc(rb_error_msg, default_internal_enc);
|
87
|
+
rb_sql_state = rb_str_export_to_enc(rb_sql_state, default_internal_enc);
|
88
|
+
}
|
137
89
|
#endif
|
138
90
|
|
139
|
-
e =
|
91
|
+
VALUE e = rb_exc_new3(cMysql2Error, rb_error_msg);
|
140
92
|
rb_funcall(e, intern_error_number_eql, 1, UINT2NUM(mysql_errno(wrapper->client)));
|
141
93
|
rb_funcall(e, intern_sql_state_eql, 1, rb_sql_state);
|
142
94
|
rb_exc_raise(e);
|
143
95
|
return Qnil;
|
144
96
|
}
|
145
97
|
|
146
|
-
static
|
98
|
+
static VALUE nogvl_init(void *ptr) {
|
147
99
|
MYSQL *client;
|
148
|
-
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
|
149
100
|
|
150
101
|
/* may initialize embedded server and read /etc/services off disk */
|
151
|
-
client = mysql_init(
|
152
|
-
|
153
|
-
if (client) mysql2_set_local_infile(client, wrapper);
|
154
|
-
|
155
|
-
return (void*)(client ? Qtrue : Qfalse);
|
102
|
+
client = mysql_init((MYSQL *)ptr);
|
103
|
+
return client ? Qtrue : Qfalse;
|
156
104
|
}
|
157
105
|
|
158
|
-
static
|
106
|
+
static VALUE nogvl_connect(void *ptr) {
|
159
107
|
struct nogvl_connect_args *args = ptr;
|
160
108
|
MYSQL *client;
|
161
109
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
110
|
+
do {
|
111
|
+
client = mysql_real_connect(args->mysql, args->host,
|
112
|
+
args->user, args->passwd,
|
113
|
+
args->db, args->port, args->unix_socket,
|
114
|
+
args->client_flag);
|
115
|
+
} while (! client && errno == EINTR && (errno = 0) == 0);
|
166
116
|
|
167
|
-
return
|
117
|
+
return client ? Qtrue : Qfalse;
|
168
118
|
}
|
169
119
|
|
120
|
+
static VALUE nogvl_close(void *ptr) {
|
121
|
+
mysql_client_wrapper *wrapper;
|
170
122
|
#ifndef _WIN32
|
171
|
-
|
172
|
-
* Redirect clientfd to /dev/null for mysql_close and SSL_close to write,
|
173
|
-
* shutdown, and close. The hack is needed to prevent shutdown() from breaking
|
174
|
-
* a socket that may be in use by the parent or other processes after fork.
|
175
|
-
*
|
176
|
-
* /dev/null is used to absorb writes; previously a dummy socket was used, but
|
177
|
-
* it could not abosrb writes and caused openssl to go into an infinite loop.
|
178
|
-
*
|
179
|
-
* Returns Qtrue or Qfalse (success or failure)
|
180
|
-
*
|
181
|
-
* Note: if this function is needed on Windows, use "nul" instead of "/dev/null"
|
182
|
-
*/
|
183
|
-
static VALUE invalidate_fd(int clientfd)
|
184
|
-
{
|
185
|
-
#ifdef SOCK_CLOEXEC
|
186
|
-
/* Atomically set CLOEXEC on the new FD in case another thread forks */
|
187
|
-
int sockfd = open("/dev/null", O_RDWR | O_CLOEXEC);
|
188
|
-
if (sockfd < 0) {
|
189
|
-
/* Maybe SOCK_CLOEXEC is defined but not available on this kernel */
|
190
|
-
int sockfd = open("/dev/null", O_RDWR);
|
191
|
-
fcntl(sockfd, F_SETFD, FD_CLOEXEC);
|
192
|
-
}
|
193
|
-
#else
|
194
|
-
/* Well we don't have SOCK_CLOEXEC, so just set FD_CLOEXEC quickly */
|
195
|
-
int sockfd = open("/dev/null", O_RDWR);
|
196
|
-
fcntl(sockfd, F_SETFD, FD_CLOEXEC);
|
123
|
+
int flags;
|
197
124
|
#endif
|
125
|
+
wrapper = ptr;
|
126
|
+
if (!wrapper->closed) {
|
127
|
+
wrapper->closed = 1;
|
198
128
|
|
199
|
-
if (sockfd < 0) {
|
200
129
|
/*
|
201
|
-
*
|
202
|
-
* a
|
203
|
-
*
|
130
|
+
* we'll send a QUIT message to the server, but that message is more of a
|
131
|
+
* formality than a hard requirement since the socket is getting shutdown
|
132
|
+
* anyways, so ensure the socket write does not block our interpreter
|
133
|
+
*
|
134
|
+
*
|
135
|
+
* if the socket is dead we have no chance of blocking,
|
136
|
+
* so ignore any potential fcntl errors since they don't matter
|
204
137
|
*/
|
205
|
-
return Qfalse;
|
206
|
-
}
|
207
|
-
|
208
|
-
dup2(sockfd, clientfd);
|
209
|
-
close(sockfd);
|
210
|
-
|
211
|
-
return Qtrue;
|
212
|
-
}
|
213
|
-
#endif /* _WIN32 */
|
214
|
-
|
215
|
-
static void *nogvl_close(void *ptr) {
|
216
|
-
mysql_client_wrapper *wrapper;
|
217
|
-
wrapper = ptr;
|
218
|
-
if (wrapper->connected) {
|
219
|
-
wrapper->active_thread = Qnil;
|
220
|
-
wrapper->connected = 0;
|
221
138
|
#ifndef _WIN32
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
|
230
|
-
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, leaking some memory\n");
|
231
|
-
close(wrapper->client->net.fd);
|
232
|
-
return NULL;
|
233
|
-
}
|
139
|
+
flags = fcntl(wrapper->client->net.fd, F_GETFL);
|
140
|
+
if (flags > 0 && !(flags & O_NONBLOCK))
|
141
|
+
fcntl(wrapper->client->net.fd, F_SETFL, flags | O_NONBLOCK);
|
142
|
+
#else
|
143
|
+
u_long iMode;
|
144
|
+
iMode = 1;
|
145
|
+
ioctlsocket(wrapper->client->net.fd, FIONBIO, &iMode);
|
234
146
|
#endif
|
235
147
|
|
236
|
-
mysql_close(wrapper->client);
|
148
|
+
mysql_close(wrapper->client);
|
149
|
+
xfree(wrapper->client);
|
237
150
|
}
|
238
151
|
|
239
|
-
return
|
152
|
+
return Qnil;
|
240
153
|
}
|
241
154
|
|
242
|
-
static void rb_mysql_client_free(void *ptr) {
|
155
|
+
static void rb_mysql_client_free(void * ptr) {
|
243
156
|
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
|
244
|
-
decr_mysql2_client(wrapper);
|
245
|
-
}
|
246
157
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
if (wrapper->refcount == 0) {
|
251
|
-
nogvl_close(wrapper);
|
252
|
-
xfree(wrapper->client);
|
253
|
-
xfree(wrapper);
|
254
|
-
}
|
158
|
+
nogvl_close(wrapper);
|
159
|
+
|
160
|
+
xfree(ptr);
|
255
161
|
}
|
256
162
|
|
257
163
|
static VALUE allocate(VALUE klass) {
|
@@ -259,25 +165,13 @@ static VALUE allocate(VALUE klass) {
|
|
259
165
|
mysql_client_wrapper * wrapper;
|
260
166
|
obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
|
261
167
|
wrapper->encoding = Qnil;
|
262
|
-
wrapper->
|
263
|
-
wrapper->
|
264
|
-
wrapper->reconnect_enabled = 0;
|
265
|
-
wrapper->connect_timeout = 0;
|
266
|
-
wrapper->connected = 0; /* means that a database connection is open */
|
267
|
-
wrapper->initialized = 0; /* means that that the wrapper is initialized */
|
268
|
-
wrapper->refcount = 1;
|
168
|
+
wrapper->active = 0;
|
169
|
+
wrapper->closed = 1;
|
269
170
|
wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
|
270
171
|
return obj;
|
271
172
|
}
|
272
173
|
|
273
|
-
|
274
|
-
* Mysql2::Client.escape(string)
|
275
|
-
*
|
276
|
-
* Escape +string+ so that it may be used in a SQL statement.
|
277
|
-
* Note that this escape method is not connection encoding aware.
|
278
|
-
* If you need encoding support use Mysql2::Client#escape instead.
|
279
|
-
*/
|
280
|
-
static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
|
174
|
+
static VALUE rb_mysql_client_escape(VALUE klass, VALUE str) {
|
281
175
|
unsigned char *newStr;
|
282
176
|
VALUE rb_str;
|
283
177
|
unsigned long newLen, oldLen;
|
@@ -289,7 +183,7 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
|
|
289
183
|
|
290
184
|
newLen = mysql_escape_string((char *)newStr, StringValuePtr(str), oldLen);
|
291
185
|
if (newLen == oldLen) {
|
292
|
-
|
186
|
+
// no need to return a new ruby string if nothing changed
|
293
187
|
xfree(newStr);
|
294
188
|
return str;
|
295
189
|
} else {
|
@@ -302,81 +196,24 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
|
|
302
196
|
}
|
303
197
|
}
|
304
198
|
|
305
|
-
static VALUE rb_mysql_client_warning_count(VALUE self) {
|
306
|
-
unsigned int warning_count;
|
307
|
-
GET_CLIENT(self);
|
308
|
-
|
309
|
-
warning_count = mysql_warning_count(wrapper->client);
|
310
|
-
|
311
|
-
return UINT2NUM(warning_count);
|
312
|
-
}
|
313
|
-
|
314
|
-
static VALUE rb_mysql_info(VALUE self) {
|
315
|
-
const char *info;
|
316
|
-
VALUE rb_str;
|
317
|
-
GET_CLIENT(self);
|
318
|
-
|
319
|
-
info = mysql_info(wrapper->client);
|
320
|
-
|
321
|
-
if (info == NULL) {
|
322
|
-
return Qnil;
|
323
|
-
}
|
324
|
-
|
325
|
-
rb_str = rb_str_new2(info);
|
326
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
327
|
-
rb_enc_associate(rb_str, rb_utf8_encoding());
|
328
|
-
#endif
|
329
|
-
|
330
|
-
return rb_str;
|
331
|
-
}
|
332
|
-
|
333
199
|
static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags) {
|
334
200
|
struct nogvl_connect_args args;
|
335
|
-
time_t start_time, end_time;
|
336
|
-
unsigned int elapsed_time, connect_timeout;
|
337
|
-
VALUE rv;
|
338
201
|
GET_CLIENT(self);
|
339
202
|
|
340
|
-
args.host = NIL_P(host) ?
|
203
|
+
args.host = NIL_P(host) ? "localhost" : StringValuePtr(host);
|
341
204
|
args.unix_socket = NIL_P(socket) ? NULL : StringValuePtr(socket);
|
342
|
-
args.port = NIL_P(port) ?
|
205
|
+
args.port = NIL_P(port) ? 3306 : NUM2INT(port);
|
343
206
|
args.user = NIL_P(user) ? NULL : StringValuePtr(user);
|
344
207
|
args.passwd = NIL_P(pass) ? NULL : StringValuePtr(pass);
|
345
208
|
args.db = NIL_P(database) ? NULL : StringValuePtr(database);
|
346
209
|
args.mysql = wrapper->client;
|
347
210
|
args.client_flag = NUM2ULONG(flags);
|
348
211
|
|
349
|
-
if (
|
350
|
-
|
351
|
-
|
352
|
-
if (rv == Qfalse) {
|
353
|
-
while (rv == Qfalse && errno == EINTR) {
|
354
|
-
if (wrapper->connect_timeout) {
|
355
|
-
time(&end_time);
|
356
|
-
/* avoid long connect timeout from system time changes */
|
357
|
-
if (end_time < start_time)
|
358
|
-
start_time = end_time;
|
359
|
-
elapsed_time = end_time - start_time;
|
360
|
-
/* avoid an early timeout due to time truncating milliseconds off the start time */
|
361
|
-
if (elapsed_time > 0)
|
362
|
-
elapsed_time--;
|
363
|
-
if (elapsed_time >= wrapper->connect_timeout)
|
364
|
-
break;
|
365
|
-
connect_timeout = wrapper->connect_timeout - elapsed_time;
|
366
|
-
mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
|
367
|
-
}
|
368
|
-
errno = 0;
|
369
|
-
rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0);
|
370
|
-
}
|
371
|
-
/* restore the connect timeout for reconnecting */
|
372
|
-
if (wrapper->connect_timeout)
|
373
|
-
mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &wrapper->connect_timeout);
|
374
|
-
if (rv == Qfalse)
|
375
|
-
return rb_raise_mysql2_error(wrapper);
|
212
|
+
if (rb_thread_blocking_region(nogvl_connect, &args, RUBY_UBF_IO, 0) == Qfalse) {
|
213
|
+
// unable to connect
|
214
|
+
return rb_raise_mysql2_error(wrapper);
|
376
215
|
}
|
377
216
|
|
378
|
-
wrapper->server_version = mysql_get_server_version(wrapper->client);
|
379
|
-
wrapper->connected = 1;
|
380
217
|
return self;
|
381
218
|
}
|
382
219
|
|
@@ -389,8 +226,8 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
389
226
|
static VALUE rb_mysql_client_close(VALUE self) {
|
390
227
|
GET_CLIENT(self);
|
391
228
|
|
392
|
-
if (wrapper->
|
393
|
-
|
229
|
+
if (!wrapper->closed) {
|
230
|
+
rb_thread_blocking_region(nogvl_close, wrapper, RUBY_UBF_IO, 0);
|
394
231
|
}
|
395
232
|
|
396
233
|
return Qnil;
|
@@ -401,24 +238,15 @@ static VALUE rb_mysql_client_close(VALUE self) {
|
|
401
238
|
* enough to fit in a socket buffer, but sometimes large UPDATE and
|
402
239
|
* INSERTs will cause the process to block
|
403
240
|
*/
|
404
|
-
static
|
241
|
+
static VALUE nogvl_send_query(void *ptr) {
|
405
242
|
struct nogvl_send_query_args *args = ptr;
|
406
243
|
int rv;
|
244
|
+
const char *sql = StringValuePtr(args->sql);
|
245
|
+
long sql_len = RSTRING_LEN(args->sql);
|
407
246
|
|
408
|
-
rv = mysql_send_query(args->mysql,
|
247
|
+
rv = mysql_send_query(args->mysql, sql, sql_len);
|
409
248
|
|
410
|
-
return
|
411
|
-
}
|
412
|
-
|
413
|
-
static VALUE do_send_query(void *args) {
|
414
|
-
struct nogvl_send_query_args *query_args = args;
|
415
|
-
mysql_client_wrapper *wrapper = query_args->wrapper;
|
416
|
-
if ((VALUE)rb_thread_call_without_gvl(nogvl_send_query, args, RUBY_UBF_IO, 0) == Qfalse) {
|
417
|
-
/* an error occurred, we're not active anymore */
|
418
|
-
MARK_CONN_INACTIVE(self);
|
419
|
-
return rb_raise_mysql2_error(wrapper);
|
420
|
-
}
|
421
|
-
return Qnil;
|
249
|
+
return rv == 0 ? Qtrue : Qfalse;
|
422
250
|
}
|
423
251
|
|
424
252
|
/*
|
@@ -426,129 +254,117 @@ static VALUE do_send_query(void *args) {
|
|
426
254
|
* response can overflow the socket buffers and cause us to eventually
|
427
255
|
* block while calling mysql_read_query_result
|
428
256
|
*/
|
429
|
-
static
|
257
|
+
static VALUE nogvl_read_query_result(void *ptr) {
|
430
258
|
MYSQL * client = ptr;
|
431
259
|
my_bool res = mysql_read_query_result(client);
|
432
260
|
|
433
|
-
return
|
434
|
-
}
|
435
|
-
|
436
|
-
static void *nogvl_do_result(void *ptr, char use_result) {
|
437
|
-
mysql_client_wrapper *wrapper;
|
438
|
-
MYSQL_RES *result;
|
439
|
-
|
440
|
-
wrapper = (mysql_client_wrapper *)ptr;
|
441
|
-
if(use_result) {
|
442
|
-
result = mysql_use_result(wrapper->client);
|
443
|
-
} else {
|
444
|
-
result = mysql_store_result(wrapper->client);
|
445
|
-
}
|
446
|
-
|
447
|
-
/* once our result is stored off, this connection is
|
448
|
-
ready for another command to be issued */
|
449
|
-
wrapper->active_thread = Qnil;
|
450
|
-
|
451
|
-
return result;
|
261
|
+
return res == 0 ? Qtrue : Qfalse;
|
452
262
|
}
|
453
263
|
|
454
264
|
/* mysql_store_result may (unlikely) read rows off the socket */
|
455
|
-
static
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
static void *nogvl_use_result(void *ptr) {
|
460
|
-
return nogvl_do_result(ptr, 1);
|
265
|
+
static VALUE nogvl_store_result(void *ptr) {
|
266
|
+
MYSQL * client = ptr;
|
267
|
+
return (VALUE)mysql_store_result(client);
|
461
268
|
}
|
462
269
|
|
463
|
-
/* call-seq:
|
464
|
-
* client.async_result
|
465
|
-
*
|
466
|
-
* Returns the result for the last async issued query.
|
467
|
-
*/
|
468
270
|
static VALUE rb_mysql_client_async_result(VALUE self) {
|
469
271
|
MYSQL_RES * result;
|
470
272
|
VALUE resultObj;
|
471
|
-
|
273
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
274
|
+
mysql2_result_wrapper * result_wrapper;
|
275
|
+
#endif
|
472
276
|
GET_CLIENT(self);
|
473
277
|
|
474
|
-
|
475
|
-
if (
|
476
|
-
|
477
|
-
|
478
|
-
REQUIRE_CONNECTED(wrapper);
|
479
|
-
if ((VALUE)rb_thread_call_without_gvl(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
|
480
|
-
/* an error occurred, mark this connection inactive */
|
278
|
+
REQUIRE_OPEN_DB(wrapper);
|
279
|
+
if (rb_thread_blocking_region(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
|
280
|
+
// an error occurred, mark this connection inactive
|
481
281
|
MARK_CONN_INACTIVE(self);
|
482
282
|
return rb_raise_mysql2_error(wrapper);
|
483
283
|
}
|
484
284
|
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
|
490
|
-
}
|
285
|
+
result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, wrapper->client, RUBY_UBF_IO, 0);
|
286
|
+
|
287
|
+
// we have our result, mark this connection inactive
|
288
|
+
MARK_CONN_INACTIVE(self);
|
491
289
|
|
492
290
|
if (result == NULL) {
|
493
|
-
if (
|
494
|
-
MARK_CONN_INACTIVE(self);
|
291
|
+
if (mysql_field_count(wrapper->client) != 0) {
|
495
292
|
rb_raise_mysql2_error(wrapper);
|
496
293
|
}
|
497
|
-
/* no data and no error, so query was not a SELECT */
|
498
294
|
return Qnil;
|
499
295
|
}
|
500
296
|
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result);
|
297
|
+
resultObj = rb_mysql_result_to_obj(result);
|
298
|
+
// pass-through query options for result construction later
|
299
|
+
rb_iv_set(resultObj, "@query_options", rb_funcall(rb_iv_get(self, "@query_options"), rb_intern("dup"), 0));
|
505
300
|
|
301
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
302
|
+
GetMysql2Result(resultObj, result_wrapper);
|
303
|
+
result_wrapper->encoding = wrapper->encoding;
|
304
|
+
#endif
|
506
305
|
return resultObj;
|
507
306
|
}
|
508
307
|
|
509
|
-
|
510
|
-
struct
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
308
|
+
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
|
309
|
+
struct nogvl_send_query_args args;
|
310
|
+
fd_set fdset;
|
311
|
+
int fd, retval;
|
312
|
+
int async = 0;
|
313
|
+
VALUE opts, defaults, read_timeout;
|
314
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
315
|
+
rb_encoding *conn_enc;
|
316
|
+
#endif
|
317
|
+
struct timeval tv;
|
318
|
+
struct timeval* tvp;
|
319
|
+
long int sec;
|
320
|
+
VALUE result;
|
516
321
|
GET_CLIENT(self);
|
517
322
|
|
518
|
-
wrapper
|
519
|
-
|
323
|
+
REQUIRE_OPEN_DB(wrapper);
|
324
|
+
args.mysql = wrapper->client;
|
520
325
|
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
326
|
+
// see if this connection is still waiting on a result from a previous query
|
327
|
+
if (wrapper->active == 0) {
|
328
|
+
// mark this connection active
|
329
|
+
wrapper->active = 1;
|
330
|
+
} else {
|
331
|
+
rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
|
527
332
|
}
|
528
333
|
|
529
|
-
|
334
|
+
defaults = rb_iv_get(self, "@query_options");
|
335
|
+
if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
|
336
|
+
opts = rb_funcall(defaults, intern_merge, 1, opts);
|
337
|
+
rb_iv_set(self, "@query_options", opts);
|
530
338
|
|
531
|
-
|
532
|
-
|
339
|
+
if (rb_hash_aref(opts, sym_async) == Qtrue) {
|
340
|
+
async = 1;
|
341
|
+
}
|
342
|
+
} else {
|
343
|
+
opts = defaults;
|
344
|
+
}
|
533
345
|
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
346
|
+
Check_Type(args.sql, T_STRING);
|
347
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
348
|
+
conn_enc = rb_to_encoding(wrapper->encoding);
|
349
|
+
// ensure the string is in the encoding the connection is expecting
|
350
|
+
args.sql = rb_str_export_to_enc(args.sql, conn_enc);
|
351
|
+
#endif
|
352
|
+
|
353
|
+
if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
|
354
|
+
// an error occurred, we're not active anymore
|
355
|
+
MARK_CONN_INACTIVE(self);
|
356
|
+
return rb_raise_mysql2_error(wrapper);
|
357
|
+
}
|
541
358
|
|
542
|
-
|
543
|
-
read_timeout = rb_iv_get(async_args->self, "@read_timeout");
|
359
|
+
read_timeout = rb_iv_get(self, "@read_timeout");
|
544
360
|
|
545
361
|
tvp = NULL;
|
546
362
|
if (!NIL_P(read_timeout)) {
|
547
363
|
Check_Type(read_timeout, T_FIXNUM);
|
548
364
|
tvp = &tv;
|
549
365
|
sec = FIX2INT(read_timeout);
|
550
|
-
|
551
|
-
|
366
|
+
// TODO: support partial seconds?
|
367
|
+
// also, this check is here for sanity, we also check up in Ruby
|
552
368
|
if (sec >= 0) {
|
553
369
|
tvp->tv_sec = sec;
|
554
370
|
} else {
|
@@ -557,163 +373,55 @@ static VALUE do_query(void *args) {
|
|
557
373
|
tvp->tv_usec = 0;
|
558
374
|
}
|
559
375
|
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
if (retval < 0) {
|
568
|
-
rb_sys_fail(0);
|
569
|
-
}
|
570
|
-
|
571
|
-
if (retval > 0) {
|
572
|
-
break;
|
573
|
-
}
|
574
|
-
}
|
575
|
-
|
576
|
-
return Qnil;
|
577
|
-
}
|
578
|
-
#else
|
579
|
-
static VALUE finish_and_mark_inactive(void *args) {
|
580
|
-
VALUE self;
|
581
|
-
MYSQL_RES *result;
|
582
|
-
|
583
|
-
self = (VALUE)args;
|
584
|
-
|
585
|
-
GET_CLIENT(self);
|
586
|
-
|
587
|
-
if (!NIL_P(wrapper->active_thread)) {
|
588
|
-
/* if we got here, the result hasn't been read off the wire yet
|
589
|
-
so lets do that and then throw it away because we have no way
|
590
|
-
of getting it back up to the caller from here */
|
591
|
-
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
|
592
|
-
mysql_free_result(result);
|
593
|
-
|
594
|
-
wrapper->active_thread = Qnil;
|
595
|
-
}
|
376
|
+
if (!async) {
|
377
|
+
// the below code is largely from do_mysql
|
378
|
+
// http://github.com/datamapper/do
|
379
|
+
fd = wrapper->client->net.fd;
|
380
|
+
for(;;) {
|
381
|
+
int fd_set_fd = fd;
|
596
382
|
|
597
|
-
|
598
|
-
|
383
|
+
#ifdef _WIN32
|
384
|
+
WSAPROTOCOL_INFO wsa_pi;
|
385
|
+
// dupicate the SOCKET from libmysql
|
386
|
+
int r = WSADuplicateSocket(fd, GetCurrentProcessId(), &wsa_pi);
|
387
|
+
SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
|
388
|
+
// create the CRT fd so ruby can get back to the SOCKET
|
389
|
+
fd_set_fd = _open_osfhandle(s, O_RDWR|O_BINARY);
|
599
390
|
#endif
|
600
391
|
|
601
|
-
|
602
|
-
|
603
|
-
*
|
604
|
-
* When using MULTI_STATEMENTS support, calling this will throw
|
605
|
-
* away any unprocessed results as fast as it can in order to
|
606
|
-
* put the connection back into a state where queries can be issued
|
607
|
-
* again.
|
608
|
-
*/
|
609
|
-
static VALUE rb_mysql_client_abandon_results(VALUE self) {
|
610
|
-
MYSQL_RES *result;
|
611
|
-
int ret;
|
392
|
+
FD_ZERO(&fdset);
|
393
|
+
FD_SET(fd_set_fd, &fdset);
|
612
394
|
|
613
|
-
|
395
|
+
retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp);
|
614
396
|
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
|
622
|
-
|
623
|
-
if (result != NULL) {
|
624
|
-
mysql_free_result(result);
|
625
|
-
}
|
626
|
-
}
|
627
|
-
|
628
|
-
return Qnil;
|
629
|
-
}
|
630
|
-
|
631
|
-
/* call-seq:
|
632
|
-
* client.query(sql, options = {})
|
633
|
-
*
|
634
|
-
* Query the database with +sql+, with optional +options+. For the possible
|
635
|
-
* options, see @@default_query_options on the Mysql2::Client class.
|
636
|
-
*/
|
637
|
-
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
|
638
|
-
#ifndef _WIN32
|
639
|
-
struct async_query_args async_args;
|
640
|
-
#endif
|
641
|
-
struct nogvl_send_query_args args;
|
642
|
-
int async = 0;
|
643
|
-
VALUE opts, current;
|
644
|
-
VALUE thread_current = rb_thread_current();
|
645
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
646
|
-
rb_encoding *conn_enc;
|
397
|
+
#ifdef _WIN32
|
398
|
+
// cleanup the CRT fd
|
399
|
+
_close(fd_set_fd);
|
400
|
+
// cleanup the duplicated SOCKET
|
401
|
+
closesocket(s);
|
647
402
|
#endif
|
648
|
-
GET_CLIENT(self);
|
649
|
-
|
650
|
-
REQUIRE_CONNECTED(wrapper);
|
651
|
-
args.mysql = wrapper->client;
|
652
403
|
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
rb_iv_set(self, "@current_query_options", current);
|
404
|
+
if (retval == 0) {
|
405
|
+
rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
|
406
|
+
}
|
657
407
|
|
658
|
-
|
659
|
-
|
408
|
+
if (retval < 0) {
|
409
|
+
rb_sys_fail(0);
|
410
|
+
}
|
660
411
|
|
661
|
-
|
662
|
-
|
412
|
+
if (retval > 0) {
|
413
|
+
break;
|
414
|
+
}
|
663
415
|
}
|
664
|
-
}
|
665
416
|
|
666
|
-
|
667
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
668
|
-
conn_enc = rb_to_encoding(wrapper->encoding);
|
669
|
-
/* ensure the string is in the encoding the connection is expecting */
|
670
|
-
args.sql = rb_str_export_to_enc(args.sql, conn_enc);
|
671
|
-
#endif
|
672
|
-
args.sql_ptr = StringValuePtr(args.sql);
|
673
|
-
args.sql_len = RSTRING_LEN(args.sql);
|
674
|
-
|
675
|
-
/* see if this connection is still waiting on a result from a previous query */
|
676
|
-
if (NIL_P(wrapper->active_thread)) {
|
677
|
-
/* mark this connection active */
|
678
|
-
wrapper->active_thread = thread_current;
|
679
|
-
} else if (wrapper->active_thread == thread_current) {
|
680
|
-
rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
|
681
|
-
} else {
|
682
|
-
VALUE inspect = rb_inspect(wrapper->active_thread);
|
683
|
-
const char *thr = StringValueCStr(inspect);
|
684
|
-
|
685
|
-
rb_raise(cMysql2Error, "This connection is in use by: %s", thr);
|
686
|
-
RB_GC_GUARD(inspect);
|
687
|
-
}
|
688
|
-
|
689
|
-
args.wrapper = wrapper;
|
690
|
-
|
691
|
-
#ifndef _WIN32
|
692
|
-
rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);
|
693
|
-
|
694
|
-
if (!async) {
|
695
|
-
async_args.fd = wrapper->client->net.fd;
|
696
|
-
async_args.self = self;
|
417
|
+
result = rb_mysql_client_async_result(self);
|
697
418
|
|
698
|
-
|
699
|
-
|
700
|
-
return rb_mysql_client_async_result(self);
|
419
|
+
return result;
|
701
420
|
} else {
|
702
421
|
return Qnil;
|
703
422
|
}
|
704
|
-
#else
|
705
|
-
do_send_query(&args);
|
706
|
-
|
707
|
-
/* this will just block until the result is ready */
|
708
|
-
return rb_ensure(rb_mysql_client_async_result, self, finish_and_mark_inactive, self);
|
709
|
-
#endif
|
710
423
|
}
|
711
424
|
|
712
|
-
/* call-seq:
|
713
|
-
* client.escape(string)
|
714
|
-
*
|
715
|
-
* Escape +string+ so that it may be used in a SQL statement.
|
716
|
-
*/
|
717
425
|
static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
718
426
|
unsigned char *newStr;
|
719
427
|
VALUE rb_str;
|
@@ -724,12 +432,12 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
724
432
|
#endif
|
725
433
|
GET_CLIENT(self);
|
726
434
|
|
727
|
-
|
435
|
+
REQUIRE_OPEN_DB(wrapper);
|
728
436
|
Check_Type(str, T_STRING);
|
729
437
|
#ifdef HAVE_RUBY_ENCODING_H
|
730
438
|
default_internal_enc = rb_default_internal_encoding();
|
731
439
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
732
|
-
|
440
|
+
// ensure the string is in the encoding the connection is expecting
|
733
441
|
str = rb_str_export_to_enc(str, conn_enc);
|
734
442
|
#endif
|
735
443
|
|
@@ -738,7 +446,7 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
738
446
|
|
739
447
|
newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, StringValuePtr(str), oldLen);
|
740
448
|
if (newLen == oldLen) {
|
741
|
-
|
449
|
+
// no need to return a new ruby string if nothing changed
|
742
450
|
xfree(newStr);
|
743
451
|
return str;
|
744
452
|
} else {
|
@@ -754,102 +462,13 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
754
462
|
}
|
755
463
|
}
|
756
464
|
|
757
|
-
static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
758
|
-
int result;
|
759
|
-
const void *retval = NULL;
|
760
|
-
unsigned int intval = 0;
|
761
|
-
const char * charval = NULL;
|
762
|
-
my_bool boolval;
|
763
|
-
|
764
|
-
GET_CLIENT(self);
|
765
|
-
|
766
|
-
REQUIRE_NOT_CONNECTED(wrapper);
|
767
|
-
|
768
|
-
if (NIL_P(value))
|
769
|
-
return Qfalse;
|
770
|
-
|
771
|
-
switch(opt) {
|
772
|
-
case MYSQL_OPT_CONNECT_TIMEOUT:
|
773
|
-
intval = NUM2UINT(value);
|
774
|
-
retval = &intval;
|
775
|
-
break;
|
776
|
-
|
777
|
-
case MYSQL_OPT_READ_TIMEOUT:
|
778
|
-
intval = NUM2UINT(value);
|
779
|
-
retval = &intval;
|
780
|
-
break;
|
781
|
-
|
782
|
-
case MYSQL_OPT_WRITE_TIMEOUT:
|
783
|
-
intval = NUM2UINT(value);
|
784
|
-
retval = &intval;
|
785
|
-
break;
|
786
|
-
|
787
|
-
case MYSQL_OPT_LOCAL_INFILE:
|
788
|
-
intval = (value == Qfalse ? 0 : 1);
|
789
|
-
retval = &intval;
|
790
|
-
break;
|
791
|
-
|
792
|
-
case MYSQL_OPT_RECONNECT:
|
793
|
-
boolval = (value == Qfalse ? 0 : 1);
|
794
|
-
retval = &boolval;
|
795
|
-
break;
|
796
|
-
|
797
|
-
case MYSQL_SECURE_AUTH:
|
798
|
-
boolval = (value == Qfalse ? 0 : 1);
|
799
|
-
retval = &boolval;
|
800
|
-
break;
|
801
|
-
|
802
|
-
case MYSQL_READ_DEFAULT_FILE:
|
803
|
-
charval = (const char *)StringValuePtr(value);
|
804
|
-
retval = charval;
|
805
|
-
break;
|
806
|
-
|
807
|
-
case MYSQL_READ_DEFAULT_GROUP:
|
808
|
-
charval = (const char *)StringValuePtr(value);
|
809
|
-
retval = charval;
|
810
|
-
break;
|
811
|
-
|
812
|
-
case MYSQL_INIT_COMMAND:
|
813
|
-
charval = (const char *)StringValuePtr(value);
|
814
|
-
retval = charval;
|
815
|
-
break;
|
816
|
-
|
817
|
-
default:
|
818
|
-
return Qfalse;
|
819
|
-
}
|
820
|
-
|
821
|
-
result = mysql_options(wrapper->client, opt, retval);
|
822
|
-
|
823
|
-
/* Zero means success */
|
824
|
-
if (result != 0) {
|
825
|
-
rb_warn("%s\n", mysql_error(wrapper->client));
|
826
|
-
} else {
|
827
|
-
/* Special case for options that are stored in the wrapper struct */
|
828
|
-
switch (opt) {
|
829
|
-
case MYSQL_OPT_RECONNECT:
|
830
|
-
wrapper->reconnect_enabled = boolval;
|
831
|
-
break;
|
832
|
-
case MYSQL_OPT_CONNECT_TIMEOUT:
|
833
|
-
wrapper->connect_timeout = intval;
|
834
|
-
break;
|
835
|
-
}
|
836
|
-
}
|
837
|
-
|
838
|
-
return (result == 0) ? Qtrue : Qfalse;
|
839
|
-
}
|
840
|
-
|
841
|
-
/* call-seq:
|
842
|
-
* client.info
|
843
|
-
*
|
844
|
-
* Returns a string that represents the client library version.
|
845
|
-
*/
|
846
465
|
static VALUE rb_mysql_client_info(VALUE self) {
|
847
466
|
VALUE version, client_info;
|
848
467
|
#ifdef HAVE_RUBY_ENCODING_H
|
849
468
|
rb_encoding *default_internal_enc;
|
850
469
|
rb_encoding *conn_enc;
|
851
|
-
GET_CLIENT(self);
|
852
470
|
#endif
|
471
|
+
GET_CLIENT(self);
|
853
472
|
version = rb_hash_new();
|
854
473
|
|
855
474
|
#ifdef HAVE_RUBY_ENCODING_H
|
@@ -869,11 +488,6 @@ static VALUE rb_mysql_client_info(VALUE self) {
|
|
869
488
|
return version;
|
870
489
|
}
|
871
490
|
|
872
|
-
/* call-seq:
|
873
|
-
* client.server_info
|
874
|
-
*
|
875
|
-
* Returns a string that represents the server version number
|
876
|
-
*/
|
877
491
|
static VALUE rb_mysql_client_server_info(VALUE self) {
|
878
492
|
VALUE version, server_info;
|
879
493
|
#ifdef HAVE_RUBY_ENCODING_H
|
@@ -882,7 +496,7 @@ static VALUE rb_mysql_client_server_info(VALUE self) {
|
|
882
496
|
#endif
|
883
497
|
GET_CLIENT(self);
|
884
498
|
|
885
|
-
|
499
|
+
REQUIRE_OPEN_DB(wrapper);
|
886
500
|
#ifdef HAVE_RUBY_ENCODING_H
|
887
501
|
default_internal_enc = rb_default_internal_encoding();
|
888
502
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
@@ -901,48 +515,34 @@ static VALUE rb_mysql_client_server_info(VALUE self) {
|
|
901
515
|
return version;
|
902
516
|
}
|
903
517
|
|
904
|
-
/* call-seq:
|
905
|
-
* client.socket
|
906
|
-
*
|
907
|
-
* Return the file descriptor number for this client.
|
908
|
-
*/
|
909
518
|
static VALUE rb_mysql_client_socket(VALUE self) {
|
910
519
|
GET_CLIENT(self);
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
520
|
+
REQUIRE_OPEN_DB(wrapper);
|
521
|
+
int fd_set_fd = wrapper->client->net.fd;
|
522
|
+
#ifdef _WIN32
|
523
|
+
WSAPROTOCOL_INFO wsa_pi;
|
524
|
+
// dupicate the SOCKET from libmysql
|
525
|
+
int r = WSADuplicateSocket(wrapper->client->net.fd, GetCurrentProcessId(), &wsa_pi);
|
526
|
+
SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
|
527
|
+
// create the CRT fd so ruby can get back to the SOCKET
|
528
|
+
fd_set_fd = _open_osfhandle(s, O_RDWR|O_BINARY);
|
529
|
+
return INT2NUM(fd_set_fd);
|
918
530
|
#else
|
919
|
-
|
531
|
+
return INT2NUM(fd_set_fd);
|
920
532
|
#endif
|
921
533
|
}
|
922
534
|
|
923
|
-
/* call-seq:
|
924
|
-
* client.last_id
|
925
|
-
*
|
926
|
-
* Returns the value generated for an AUTO_INCREMENT column by the previous INSERT or UPDATE
|
927
|
-
* statement.
|
928
|
-
*/
|
929
535
|
static VALUE rb_mysql_client_last_id(VALUE self) {
|
930
536
|
GET_CLIENT(self);
|
931
|
-
|
537
|
+
REQUIRE_OPEN_DB(wrapper);
|
932
538
|
return ULL2NUM(mysql_insert_id(wrapper->client));
|
933
539
|
}
|
934
540
|
|
935
|
-
/* call-seq:
|
936
|
-
* client.affected_rows
|
937
|
-
*
|
938
|
-
* returns the number of rows changed, deleted, or inserted by the last statement
|
939
|
-
* if it was an UPDATE, DELETE, or INSERT.
|
940
|
-
*/
|
941
541
|
static VALUE rb_mysql_client_affected_rows(VALUE self) {
|
942
542
|
my_ulonglong retVal;
|
943
543
|
GET_CLIENT(self);
|
944
544
|
|
945
|
-
|
545
|
+
REQUIRE_OPEN_DB(wrapper);
|
946
546
|
retVal = mysql_affected_rows(wrapper->client);
|
947
547
|
if (retVal == (my_ulonglong)-1) {
|
948
548
|
rb_raise_mysql2_error(wrapper);
|
@@ -950,227 +550,93 @@ static VALUE rb_mysql_client_affected_rows(VALUE self) {
|
|
950
550
|
return ULL2NUM(retVal);
|
951
551
|
}
|
952
552
|
|
953
|
-
/* call-seq:
|
954
|
-
* client.thread_id
|
955
|
-
*
|
956
|
-
* Returns the thread ID of the current connection.
|
957
|
-
*/
|
958
553
|
static VALUE rb_mysql_client_thread_id(VALUE self) {
|
959
554
|
unsigned long retVal;
|
960
555
|
GET_CLIENT(self);
|
961
556
|
|
962
|
-
|
557
|
+
REQUIRE_OPEN_DB(wrapper);
|
963
558
|
retVal = mysql_thread_id(wrapper->client);
|
964
559
|
return ULL2NUM(retVal);
|
965
560
|
}
|
966
561
|
|
967
|
-
static
|
968
|
-
struct nogvl_select_db_args *args = ptr;
|
969
|
-
|
970
|
-
if (mysql_select_db(args->mysql, args->db) == 0)
|
971
|
-
return (void *)Qtrue;
|
972
|
-
else
|
973
|
-
return (void *)Qfalse;
|
974
|
-
}
|
975
|
-
|
976
|
-
/* call-seq:
|
977
|
-
* client.select_db(name)
|
978
|
-
*
|
979
|
-
* Causes the database specified by +name+ to become the default (current)
|
980
|
-
* database on the connection specified by mysql.
|
981
|
-
*/
|
982
|
-
static VALUE rb_mysql_client_select_db(VALUE self, VALUE db)
|
562
|
+
static VALUE nogvl_ping(void *ptr)
|
983
563
|
{
|
984
|
-
struct nogvl_select_db_args args;
|
985
|
-
|
986
|
-
GET_CLIENT(self);
|
987
|
-
REQUIRE_CONNECTED(wrapper);
|
988
|
-
|
989
|
-
args.mysql = wrapper->client;
|
990
|
-
args.db = StringValuePtr(db);
|
991
|
-
|
992
|
-
if (rb_thread_call_without_gvl(nogvl_select_db, &args, RUBY_UBF_IO, 0) == Qfalse)
|
993
|
-
rb_raise_mysql2_error(wrapper);
|
994
|
-
|
995
|
-
return db;
|
996
|
-
}
|
997
|
-
|
998
|
-
static void *nogvl_ping(void *ptr) {
|
999
564
|
MYSQL *client = ptr;
|
1000
565
|
|
1001
|
-
return
|
566
|
+
return mysql_ping(client) == 0 ? Qtrue : Qfalse;
|
1002
567
|
}
|
1003
568
|
|
1004
|
-
/* call-seq:
|
1005
|
-
* client.ping
|
1006
|
-
*
|
1007
|
-
* Checks whether the connection to the server is working. If the connection
|
1008
|
-
* has gone down and auto-reconnect is enabled an attempt to reconnect is made.
|
1009
|
-
* If the connection is down and auto-reconnect is disabled, ping returns an
|
1010
|
-
* error.
|
1011
|
-
*/
|
1012
569
|
static VALUE rb_mysql_client_ping(VALUE self) {
|
1013
570
|
GET_CLIENT(self);
|
1014
571
|
|
1015
|
-
if (
|
572
|
+
if (wrapper->closed) {
|
1016
573
|
return Qfalse;
|
1017
574
|
} else {
|
1018
|
-
return (
|
1019
|
-
}
|
1020
|
-
}
|
1021
|
-
|
1022
|
-
/* call-seq:
|
1023
|
-
* client.more_results?
|
1024
|
-
*
|
1025
|
-
* Returns true or false if there are more results to process.
|
1026
|
-
*/
|
1027
|
-
static VALUE rb_mysql_client_more_results(VALUE self)
|
1028
|
-
{
|
1029
|
-
GET_CLIENT(self);
|
1030
|
-
if (mysql_more_results(wrapper->client) == 0)
|
1031
|
-
return Qfalse;
|
1032
|
-
else
|
1033
|
-
return Qtrue;
|
1034
|
-
}
|
1035
|
-
|
1036
|
-
/* call-seq:
|
1037
|
-
* client.next_result
|
1038
|
-
*
|
1039
|
-
* Fetch the next result set from the server.
|
1040
|
-
* Returns nothing.
|
1041
|
-
*/
|
1042
|
-
static VALUE rb_mysql_client_next_result(VALUE self)
|
1043
|
-
{
|
1044
|
-
int ret;
|
1045
|
-
GET_CLIENT(self);
|
1046
|
-
ret = mysql_next_result(wrapper->client);
|
1047
|
-
if (ret > 0) {
|
1048
|
-
rb_raise_mysql2_error(wrapper);
|
1049
|
-
return Qfalse;
|
1050
|
-
} else if (ret == 0) {
|
1051
|
-
return Qtrue;
|
1052
|
-
} else {
|
1053
|
-
return Qfalse;
|
1054
|
-
}
|
1055
|
-
}
|
1056
|
-
|
1057
|
-
/* call-seq:
|
1058
|
-
* client.store_result
|
1059
|
-
*
|
1060
|
-
* Return the next result object from a query which
|
1061
|
-
* yielded multiple result sets.
|
1062
|
-
*/
|
1063
|
-
static VALUE rb_mysql_client_store_result(VALUE self)
|
1064
|
-
{
|
1065
|
-
MYSQL_RES * result;
|
1066
|
-
VALUE resultObj;
|
1067
|
-
VALUE current;
|
1068
|
-
GET_CLIENT(self);
|
1069
|
-
|
1070
|
-
result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
|
1071
|
-
|
1072
|
-
if (result == NULL) {
|
1073
|
-
if (mysql_errno(wrapper->client) != 0) {
|
1074
|
-
rb_raise_mysql2_error(wrapper);
|
1075
|
-
}
|
1076
|
-
/* no data and no error, so query was not a SELECT */
|
1077
|
-
return Qnil;
|
575
|
+
return rb_thread_blocking_region(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
|
1078
576
|
}
|
1079
|
-
|
1080
|
-
current = rb_hash_dup(rb_iv_get(self, "@current_query_options"));
|
1081
|
-
RB_GC_GUARD(current);
|
1082
|
-
Check_Type(current, T_HASH);
|
1083
|
-
resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result);
|
1084
|
-
|
1085
|
-
return resultObj;
|
1086
577
|
}
|
1087
578
|
|
1088
579
|
#ifdef HAVE_RUBY_ENCODING_H
|
1089
|
-
/* call-seq:
|
1090
|
-
* client.encoding
|
1091
|
-
*
|
1092
|
-
* Returns the encoding set on the client.
|
1093
|
-
*/
|
1094
580
|
static VALUE rb_mysql_client_encoding(VALUE self) {
|
1095
581
|
GET_CLIENT(self);
|
1096
582
|
return wrapper->encoding;
|
1097
583
|
}
|
1098
584
|
#endif
|
1099
585
|
|
1100
|
-
/* call-seq:
|
1101
|
-
* client.reconnect = true
|
1102
|
-
*
|
1103
|
-
* Enable or disable the automatic reconnect behavior of libmysql.
|
1104
|
-
* Read http://dev.mysql.com/doc/refman/5.5/en/auto-reconnect.html
|
1105
|
-
* for more information.
|
1106
|
-
*/
|
1107
586
|
static VALUE set_reconnect(VALUE self, VALUE value) {
|
1108
|
-
|
1109
|
-
|
587
|
+
my_bool reconnect;
|
588
|
+
GET_CLIENT(self);
|
1110
589
|
|
1111
|
-
|
1112
|
-
|
1113
|
-
}
|
590
|
+
if(!NIL_P(value)) {
|
591
|
+
reconnect = value == Qfalse ? 0 : 1;
|
1114
592
|
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
rb_raise(cMysql2Error, "connect_timeout must be a positive integer, you passed %ld", sec);
|
593
|
+
/* set default reconnect behavior */
|
594
|
+
if (mysql_options(wrapper->client, MYSQL_OPT_RECONNECT, &reconnect)) {
|
595
|
+
/* TODO: warning - unable to set reconnect behavior */
|
596
|
+
rb_warn("%s\n", mysql_error(wrapper->client));
|
597
|
+
}
|
1121
598
|
}
|
1122
|
-
return
|
599
|
+
return value;
|
1123
600
|
}
|
1124
601
|
|
1125
|
-
static VALUE
|
1126
|
-
|
1127
|
-
|
1128
|
-
sec = FIX2INT(value);
|
1129
|
-
if (sec < 0) {
|
1130
|
-
rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
|
1131
|
-
}
|
1132
|
-
/* Set the instance variable here even though _mysql_client_options
|
1133
|
-
might not succeed, because the timeout is used in other ways
|
1134
|
-
elsewhere */
|
1135
|
-
rb_iv_set(self, "@read_timeout", value);
|
1136
|
-
return _mysql_client_options(self, MYSQL_OPT_READ_TIMEOUT, value);
|
1137
|
-
}
|
602
|
+
static VALUE set_connect_timeout(VALUE self, VALUE value) {
|
603
|
+
unsigned int connect_timeout = 0;
|
604
|
+
GET_CLIENT(self);
|
1138
605
|
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
606
|
+
if(!NIL_P(value)) {
|
607
|
+
connect_timeout = NUM2INT(value);
|
608
|
+
if(0 == connect_timeout) return value;
|
609
|
+
|
610
|
+
/* set default connection timeout behavior */
|
611
|
+
if (mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout)) {
|
612
|
+
/* TODO: warning - unable to set connection timeout */
|
613
|
+
rb_warn("%s\n", mysql_error(wrapper->client));
|
614
|
+
}
|
1145
615
|
}
|
1146
|
-
return
|
616
|
+
return value;
|
1147
617
|
}
|
1148
618
|
|
1149
619
|
static VALUE set_charset_name(VALUE self, VALUE value) {
|
1150
|
-
char *charset_name;
|
620
|
+
char * charset_name;
|
1151
621
|
#ifdef HAVE_RUBY_ENCODING_H
|
1152
|
-
|
1153
|
-
const struct mysql2_mysql_enc_name_to_rb_map *mysql2rb;
|
1154
|
-
rb_encoding *enc;
|
1155
|
-
VALUE rb_enc;
|
622
|
+
VALUE new_encoding;
|
1156
623
|
#endif
|
1157
624
|
GET_CLIENT(self);
|
1158
625
|
|
1159
|
-
charset_name = RSTRING_PTR(value);
|
1160
|
-
|
1161
626
|
#ifdef HAVE_RUBY_ENCODING_H
|
1162
|
-
|
1163
|
-
|
1164
|
-
if (mysql2rb == NULL || mysql2rb->rb_name == NULL) {
|
627
|
+
new_encoding = rb_funcall(cMysql2Client, intern_encoding_from_charset, 1, value);
|
628
|
+
if (new_encoding == Qnil) {
|
1165
629
|
VALUE inspect = rb_inspect(value);
|
1166
630
|
rb_raise(cMysql2Error, "Unsupported charset: '%s'", RSTRING_PTR(inspect));
|
1167
631
|
} else {
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
632
|
+
if (wrapper->encoding == Qnil) {
|
633
|
+
wrapper->encoding = new_encoding;
|
634
|
+
}
|
1171
635
|
}
|
1172
636
|
#endif
|
1173
637
|
|
638
|
+
charset_name = StringValuePtr(value);
|
639
|
+
|
1174
640
|
if (mysql_options(wrapper->client, MYSQL_SET_CHARSET_NAME, charset_name)) {
|
1175
641
|
/* TODO: warning - unable to set charset */
|
1176
642
|
rb_warn("%s\n", mysql_error(wrapper->client));
|
@@ -1182,73 +648,48 @@ static VALUE set_charset_name(VALUE self, VALUE value) {
|
|
1182
648
|
static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE capath, VALUE cipher) {
|
1183
649
|
GET_CLIENT(self);
|
1184
650
|
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
651
|
+
if(!NIL_P(ca) || !NIL_P(key)) {
|
652
|
+
mysql_ssl_set(wrapper->client,
|
653
|
+
NIL_P(key) ? NULL : StringValuePtr(key),
|
654
|
+
NIL_P(cert) ? NULL : StringValuePtr(cert),
|
655
|
+
NIL_P(ca) ? NULL : StringValuePtr(ca),
|
656
|
+
NIL_P(capath) ? NULL : StringValuePtr(capath),
|
657
|
+
NIL_P(cipher) ? NULL : StringValuePtr(cipher));
|
658
|
+
}
|
1191
659
|
|
1192
660
|
return self;
|
1193
661
|
}
|
1194
662
|
|
1195
|
-
static VALUE
|
1196
|
-
return _mysql_client_options(self, MYSQL_SECURE_AUTH, value);
|
1197
|
-
}
|
1198
|
-
|
1199
|
-
static VALUE set_read_default_file(VALUE self, VALUE value) {
|
1200
|
-
return _mysql_client_options(self, MYSQL_READ_DEFAULT_FILE, value);
|
1201
|
-
}
|
1202
|
-
|
1203
|
-
static VALUE set_read_default_group(VALUE self, VALUE value) {
|
1204
|
-
return _mysql_client_options(self, MYSQL_READ_DEFAULT_GROUP, value);
|
1205
|
-
}
|
1206
|
-
|
1207
|
-
static VALUE set_init_command(VALUE self, VALUE value) {
|
1208
|
-
return _mysql_client_options(self, MYSQL_INIT_COMMAND, value);
|
1209
|
-
}
|
1210
|
-
|
1211
|
-
static VALUE initialize_ext(VALUE self) {
|
663
|
+
static VALUE init_connection(VALUE self) {
|
1212
664
|
GET_CLIENT(self);
|
1213
665
|
|
1214
|
-
if ((
|
666
|
+
if (rb_thread_blocking_region(nogvl_init, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
|
1215
667
|
/* TODO: warning - not enough memory? */
|
1216
668
|
return rb_raise_mysql2_error(wrapper);
|
1217
669
|
}
|
1218
670
|
|
1219
|
-
wrapper->
|
671
|
+
wrapper->closed = 0;
|
1220
672
|
return self;
|
1221
673
|
}
|
1222
674
|
|
1223
675
|
void init_mysql2_client() {
|
1224
|
-
|
1225
|
-
|
676
|
+
// verify the libmysql we're about to use was the version we were built against
|
677
|
+
// https://github.com/luislavena/mysql-gem/commit/a600a9c459597da0712f70f43736e24b484f8a99
|
1226
678
|
int i;
|
1227
679
|
int dots = 0;
|
1228
680
|
const char *lib = mysql_get_client_info();
|
1229
|
-
|
1230
|
-
for (i = 0; lib[i] != 0 && MYSQL_LINK_VERSION[i] != 0; i++) {
|
681
|
+
for (i = 0; lib[i] != 0 && MYSQL_SERVER_VERSION[i] != 0; i++) {
|
1231
682
|
if (lib[i] == '.') {
|
1232
683
|
dots++;
|
1233
|
-
|
684
|
+
// we only compare MAJOR and MINOR
|
1234
685
|
if (dots == 2) break;
|
1235
686
|
}
|
1236
|
-
if (lib[i] !=
|
1237
|
-
rb_raise(rb_eRuntimeError, "Incorrect MySQL client library version! This gem was compiled for %s but the client library is %s.",
|
687
|
+
if (lib[i] != MYSQL_SERVER_VERSION[i]) {
|
688
|
+
rb_raise(rb_eRuntimeError, "Incorrect MySQL client library version! This gem was compiled for %s but the client library is %s.", MYSQL_SERVER_VERSION, lib);
|
1238
689
|
return;
|
1239
690
|
}
|
1240
691
|
}
|
1241
692
|
|
1242
|
-
/* Initializing mysql library, so different threads could call Client.new */
|
1243
|
-
/* without race condition in the library */
|
1244
|
-
if (mysql_library_init(0, NULL, NULL) != 0) {
|
1245
|
-
rb_raise(rb_eRuntimeError, "Could not initialize MySQL client library");
|
1246
|
-
return;
|
1247
|
-
}
|
1248
|
-
|
1249
|
-
#if 0
|
1250
|
-
mMysql2 = rb_define_module("Mysql2"); Teach RDoc about Mysql2 constant.
|
1251
|
-
#endif
|
1252
693
|
cMysql2Client = rb_define_class_under(mMysql2, "Client", rb_cObject);
|
1253
694
|
|
1254
695
|
rb_define_alloc_func(cMysql2Client, allocate);
|
@@ -1257,7 +698,6 @@ void init_mysql2_client() {
|
|
1257
698
|
|
1258
699
|
rb_define_method(cMysql2Client, "close", rb_mysql_client_close, 0);
|
1259
700
|
rb_define_method(cMysql2Client, "query", rb_mysql_client_query, -1);
|
1260
|
-
rb_define_method(cMysql2Client, "abandon_results!", rb_mysql_client_abandon_results, 0);
|
1261
701
|
rb_define_method(cMysql2Client, "escape", rb_mysql_client_real_escape, 1);
|
1262
702
|
rb_define_method(cMysql2Client, "info", rb_mysql_client_info, 0);
|
1263
703
|
rb_define_method(cMysql2Client, "server_info", rb_mysql_client_server_info, 0);
|
@@ -1267,150 +707,133 @@ void init_mysql2_client() {
|
|
1267
707
|
rb_define_method(cMysql2Client, "affected_rows", rb_mysql_client_affected_rows, 0);
|
1268
708
|
rb_define_method(cMysql2Client, "thread_id", rb_mysql_client_thread_id, 0);
|
1269
709
|
rb_define_method(cMysql2Client, "ping", rb_mysql_client_ping, 0);
|
1270
|
-
rb_define_method(cMysql2Client, "select_db", rb_mysql_client_select_db, 1);
|
1271
|
-
rb_define_method(cMysql2Client, "more_results?", rb_mysql_client_more_results, 0);
|
1272
|
-
rb_define_method(cMysql2Client, "next_result", rb_mysql_client_next_result, 0);
|
1273
|
-
rb_define_method(cMysql2Client, "store_result", rb_mysql_client_store_result, 0);
|
1274
|
-
rb_define_method(cMysql2Client, "reconnect=", set_reconnect, 1);
|
1275
|
-
rb_define_method(cMysql2Client, "warning_count", rb_mysql_client_warning_count, 0);
|
1276
|
-
rb_define_method(cMysql2Client, "query_info_string", rb_mysql_info, 0);
|
1277
710
|
#ifdef HAVE_RUBY_ENCODING_H
|
1278
711
|
rb_define_method(cMysql2Client, "encoding", rb_mysql_client_encoding, 0);
|
1279
712
|
#endif
|
1280
713
|
|
714
|
+
rb_define_private_method(cMysql2Client, "reconnect=", set_reconnect, 1);
|
1281
715
|
rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
|
1282
|
-
rb_define_private_method(cMysql2Client, "read_timeout=", set_read_timeout, 1);
|
1283
|
-
rb_define_private_method(cMysql2Client, "write_timeout=", set_write_timeout, 1);
|
1284
|
-
rb_define_private_method(cMysql2Client, "local_infile=", set_local_infile, 1);
|
1285
716
|
rb_define_private_method(cMysql2Client, "charset_name=", set_charset_name, 1);
|
1286
|
-
rb_define_private_method(cMysql2Client, "secure_auth=", set_secure_auth, 1);
|
1287
|
-
rb_define_private_method(cMysql2Client, "default_file=", set_read_default_file, 1);
|
1288
|
-
rb_define_private_method(cMysql2Client, "default_group=", set_read_default_group, 1);
|
1289
|
-
rb_define_private_method(cMysql2Client, "init_command=", set_init_command, 1);
|
1290
717
|
rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
|
1291
|
-
rb_define_private_method(cMysql2Client, "
|
718
|
+
rb_define_private_method(cMysql2Client, "init_connection", init_connection, 0);
|
1292
719
|
rb_define_private_method(cMysql2Client, "connect", rb_connect, 7);
|
1293
720
|
|
721
|
+
intern_encoding_from_charset = rb_intern("encoding_from_charset");
|
722
|
+
|
1294
723
|
sym_id = ID2SYM(rb_intern("id"));
|
1295
724
|
sym_version = ID2SYM(rb_intern("version"));
|
1296
725
|
sym_async = ID2SYM(rb_intern("async"));
|
1297
726
|
sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
|
1298
727
|
sym_as = ID2SYM(rb_intern("as"));
|
1299
728
|
sym_array = ID2SYM(rb_intern("array"));
|
1300
|
-
sym_stream = ID2SYM(rb_intern("stream"));
|
1301
729
|
|
1302
730
|
intern_merge = rb_intern("merge");
|
1303
|
-
intern_merge_bang = rb_intern("merge!");
|
1304
731
|
intern_error_number_eql = rb_intern("error_number=");
|
1305
732
|
intern_sql_state_eql = rb_intern("sql_state=");
|
1306
733
|
|
1307
734
|
#ifdef CLIENT_LONG_PASSWORD
|
1308
735
|
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
|
1309
|
-
|
736
|
+
INT2NUM(CLIENT_LONG_PASSWORD));
|
1310
737
|
#endif
|
1311
738
|
|
1312
739
|
#ifdef CLIENT_FOUND_ROWS
|
1313
740
|
rb_const_set(cMysql2Client, rb_intern("FOUND_ROWS"),
|
1314
|
-
|
741
|
+
INT2NUM(CLIENT_FOUND_ROWS));
|
1315
742
|
#endif
|
1316
743
|
|
1317
744
|
#ifdef CLIENT_LONG_FLAG
|
1318
745
|
rb_const_set(cMysql2Client, rb_intern("LONG_FLAG"),
|
1319
|
-
|
746
|
+
INT2NUM(CLIENT_LONG_FLAG));
|
1320
747
|
#endif
|
1321
748
|
|
1322
749
|
#ifdef CLIENT_CONNECT_WITH_DB
|
1323
750
|
rb_const_set(cMysql2Client, rb_intern("CONNECT_WITH_DB"),
|
1324
|
-
|
751
|
+
INT2NUM(CLIENT_CONNECT_WITH_DB));
|
1325
752
|
#endif
|
1326
753
|
|
1327
754
|
#ifdef CLIENT_NO_SCHEMA
|
1328
755
|
rb_const_set(cMysql2Client, rb_intern("NO_SCHEMA"),
|
1329
|
-
|
756
|
+
INT2NUM(CLIENT_NO_SCHEMA));
|
1330
757
|
#endif
|
1331
758
|
|
1332
759
|
#ifdef CLIENT_COMPRESS
|
1333
|
-
rb_const_set(cMysql2Client, rb_intern("COMPRESS"),
|
760
|
+
rb_const_set(cMysql2Client, rb_intern("COMPRESS"), INT2NUM(CLIENT_COMPRESS));
|
1334
761
|
#endif
|
1335
762
|
|
1336
763
|
#ifdef CLIENT_ODBC
|
1337
|
-
rb_const_set(cMysql2Client, rb_intern("ODBC"),
|
764
|
+
rb_const_set(cMysql2Client, rb_intern("ODBC"), INT2NUM(CLIENT_ODBC));
|
1338
765
|
#endif
|
1339
766
|
|
1340
767
|
#ifdef CLIENT_LOCAL_FILES
|
1341
768
|
rb_const_set(cMysql2Client, rb_intern("LOCAL_FILES"),
|
1342
|
-
|
769
|
+
INT2NUM(CLIENT_LOCAL_FILES));
|
1343
770
|
#endif
|
1344
771
|
|
1345
772
|
#ifdef CLIENT_IGNORE_SPACE
|
1346
773
|
rb_const_set(cMysql2Client, rb_intern("IGNORE_SPACE"),
|
1347
|
-
|
774
|
+
INT2NUM(CLIENT_IGNORE_SPACE));
|
1348
775
|
#endif
|
1349
776
|
|
1350
777
|
#ifdef CLIENT_PROTOCOL_41
|
1351
778
|
rb_const_set(cMysql2Client, rb_intern("PROTOCOL_41"),
|
1352
|
-
|
779
|
+
INT2NUM(CLIENT_PROTOCOL_41));
|
1353
780
|
#endif
|
1354
781
|
|
1355
782
|
#ifdef CLIENT_INTERACTIVE
|
1356
783
|
rb_const_set(cMysql2Client, rb_intern("INTERACTIVE"),
|
1357
|
-
|
784
|
+
INT2NUM(CLIENT_INTERACTIVE));
|
1358
785
|
#endif
|
1359
786
|
|
1360
787
|
#ifdef CLIENT_SSL
|
1361
|
-
rb_const_set(cMysql2Client, rb_intern("SSL"),
|
788
|
+
rb_const_set(cMysql2Client, rb_intern("SSL"), INT2NUM(CLIENT_SSL));
|
1362
789
|
#endif
|
1363
790
|
|
1364
791
|
#ifdef CLIENT_IGNORE_SIGPIPE
|
1365
792
|
rb_const_set(cMysql2Client, rb_intern("IGNORE_SIGPIPE"),
|
1366
|
-
|
793
|
+
INT2NUM(CLIENT_IGNORE_SIGPIPE));
|
1367
794
|
#endif
|
1368
795
|
|
1369
796
|
#ifdef CLIENT_TRANSACTIONS
|
1370
797
|
rb_const_set(cMysql2Client, rb_intern("TRANSACTIONS"),
|
1371
|
-
|
798
|
+
INT2NUM(CLIENT_TRANSACTIONS));
|
1372
799
|
#endif
|
1373
800
|
|
1374
801
|
#ifdef CLIENT_RESERVED
|
1375
|
-
rb_const_set(cMysql2Client, rb_intern("RESERVED"),
|
802
|
+
rb_const_set(cMysql2Client, rb_intern("RESERVED"), INT2NUM(CLIENT_RESERVED));
|
1376
803
|
#endif
|
1377
804
|
|
1378
805
|
#ifdef CLIENT_SECURE_CONNECTION
|
1379
806
|
rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"),
|
1380
|
-
|
1381
|
-
#else
|
1382
|
-
/* HACK because MySQL5.7 no longer defines this constant,
|
1383
|
-
* but we're using it in our default connection flags. */
|
1384
|
-
rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"), LONG2NUM(0));
|
807
|
+
INT2NUM(CLIENT_SECURE_CONNECTION));
|
1385
808
|
#endif
|
1386
809
|
|
1387
810
|
#ifdef CLIENT_MULTI_STATEMENTS
|
1388
811
|
rb_const_set(cMysql2Client, rb_intern("MULTI_STATEMENTS"),
|
1389
|
-
|
812
|
+
INT2NUM(CLIENT_MULTI_STATEMENTS));
|
1390
813
|
#endif
|
1391
814
|
|
1392
815
|
#ifdef CLIENT_PS_MULTI_RESULTS
|
1393
816
|
rb_const_set(cMysql2Client, rb_intern("PS_MULTI_RESULTS"),
|
1394
|
-
|
817
|
+
INT2NUM(CLIENT_PS_MULTI_RESULTS));
|
1395
818
|
#endif
|
1396
819
|
|
1397
820
|
#ifdef CLIENT_SSL_VERIFY_SERVER_CERT
|
1398
821
|
rb_const_set(cMysql2Client, rb_intern("SSL_VERIFY_SERVER_CERT"),
|
1399
|
-
|
822
|
+
INT2NUM(CLIENT_SSL_VERIFY_SERVER_CERT));
|
1400
823
|
#endif
|
1401
824
|
|
1402
825
|
#ifdef CLIENT_REMEMBER_OPTIONS
|
1403
826
|
rb_const_set(cMysql2Client, rb_intern("REMEMBER_OPTIONS"),
|
1404
|
-
|
827
|
+
INT2NUM(CLIENT_REMEMBER_OPTIONS));
|
1405
828
|
#endif
|
1406
829
|
|
1407
830
|
#ifdef CLIENT_ALL_FLAGS
|
1408
831
|
rb_const_set(cMysql2Client, rb_intern("ALL_FLAGS"),
|
1409
|
-
|
832
|
+
INT2NUM(CLIENT_ALL_FLAGS));
|
1410
833
|
#endif
|
1411
834
|
|
1412
835
|
#ifdef CLIENT_BASIC_FLAGS
|
1413
836
|
rb_const_set(cMysql2Client, rb_intern("BASIC_FLAGS"),
|
1414
|
-
|
837
|
+
INT2NUM(CLIENT_BASIC_FLAGS));
|
1415
838
|
#endif
|
1416
839
|
}
|