rdp-mysql2 0.2.7.1
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 +142 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +261 -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/examples/eventmachine.rb +21 -0
- data/examples/threaded.rb +20 -0
- data/ext/mysql2/client.c +839 -0
- data/ext/mysql2/client.h +41 -0
- data/ext/mysql2/extconf.rb +72 -0
- data/ext/mysql2/mysql2_ext.c +12 -0
- data/ext/mysql2/mysql2_ext.h +42 -0
- data/ext/mysql2/result.c +488 -0
- data/ext/mysql2/result.h +20 -0
- data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +64 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +654 -0
- data/lib/active_record/fiber_patches.rb +104 -0
- data/lib/arel/engines/sql/compilers/mysql2_compiler.rb +11 -0
- data/lib/mysql2.rb +16 -0
- data/lib/mysql2/client.rb +240 -0
- data/lib/mysql2/em.rb +37 -0
- data/lib/mysql2/em_fiber.rb +31 -0
- data/lib/mysql2/error.rb +15 -0
- data/lib/mysql2/result.rb +5 -0
- data/lib/mysql2/version.rb +3 -0
- data/mysql2.gemspec +32 -0
- data/spec/em/em_fiber_spec.rb +22 -0
- data/spec/em/em_spec.rb +49 -0
- data/spec/mysql2/client_spec.rb +430 -0
- data/spec/mysql2/error_spec.rb +69 -0
- data/spec/mysql2/result_spec.rb +333 -0
- data/spec/rcov.opts +3 -0
- data/spec/spec_helper.rb +66 -0
- 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 +236 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'benchmark'
|
6
|
+
require 'active_record'
|
7
|
+
|
8
|
+
mysql2_opts = {
|
9
|
+
:adapter => 'mysql2',
|
10
|
+
:database => 'test',
|
11
|
+
:pool => 25
|
12
|
+
}
|
13
|
+
ActiveRecord::Base.establish_connection(mysql2_opts)
|
14
|
+
x = Benchmark.realtime do
|
15
|
+
threads = []
|
16
|
+
25.times do
|
17
|
+
threads << Thread.new { ActiveRecord::Base.connection.execute("select sleep(1)") }
|
18
|
+
end
|
19
|
+
threads.each {|t| t.join }
|
20
|
+
end
|
21
|
+
puts x
|
22
|
+
|
23
|
+
mysql2_opts = {
|
24
|
+
:adapter => 'mysql',
|
25
|
+
:database => 'test',
|
26
|
+
:pool => 25
|
27
|
+
}
|
28
|
+
ActiveRecord::Base.establish_connection(mysql2_opts)
|
29
|
+
x = Benchmark.realtime do
|
30
|
+
threads = []
|
31
|
+
25.times do
|
32
|
+
threads << Thread.new { ActiveRecord::Base.connection.execute("select sleep(1)") }
|
33
|
+
end
|
34
|
+
threads.each {|t| t.join }
|
35
|
+
end
|
36
|
+
puts x
|
37
|
+
|
38
|
+
# these results are similar on 1.8.7, 1.9.2 and rbx-head
|
39
|
+
#
|
40
|
+
# $ bundle exec ruby benchmarks/threaded.rb
|
41
|
+
# 1.0774750709533691
|
42
|
+
#
|
43
|
+
# and using the mysql gem
|
44
|
+
# 25.099437952041626
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift 'lib'
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'eventmachine'
|
7
|
+
require 'mysql2/em'
|
8
|
+
|
9
|
+
EM.run do
|
10
|
+
client1 = Mysql2::EM::Client.new
|
11
|
+
defer1 = client1.query "SELECT sleep(3) as first_query"
|
12
|
+
defer1.callback do |result|
|
13
|
+
puts "Result: #{result.to_a.inspect}"
|
14
|
+
end
|
15
|
+
|
16
|
+
client2 = Mysql2::EM::Client.new
|
17
|
+
defer2 = client2.query "SELECT sleep(1) second_query"
|
18
|
+
defer2.callback do |result|
|
19
|
+
puts "Result: #{result.to_a.inspect}"
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift 'lib'
|
4
|
+
require 'mysql2'
|
5
|
+
require 'timeout'
|
6
|
+
|
7
|
+
threads = []
|
8
|
+
# Should never exceed worst case 3.5 secs across all 20 threads
|
9
|
+
Timeout.timeout(3.5) do
|
10
|
+
20.times do
|
11
|
+
threads << Thread.new do
|
12
|
+
overhead = rand(3)
|
13
|
+
puts ">> thread #{Thread.current.object_id} query, #{overhead} sec overhead"
|
14
|
+
# 3 second overhead per query
|
15
|
+
Mysql2::Client.new(:host => "localhost", :username => "root").query("SELECT sleep(#{overhead}) as result")
|
16
|
+
puts "<< thread #{Thread.current.object_id} result, #{overhead} sec overhead"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
threads.each{|t| t.join }
|
20
|
+
end
|
data/ext/mysql2/client.c
ADDED
@@ -0,0 +1,839 @@
|
|
1
|
+
#include <mysql2_ext.h>
|
2
|
+
#include <client.h>
|
3
|
+
#include <errno.h>
|
4
|
+
|
5
|
+
VALUE cMysql2Client;
|
6
|
+
extern VALUE mMysql2, cMysql2Error;
|
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;
|
10
|
+
|
11
|
+
#define REQUIRE_OPEN_DB(wrapper) \
|
12
|
+
if(wrapper->closed) { \
|
13
|
+
rb_raise(cMysql2Error, "closed MySQL connection"); \
|
14
|
+
}
|
15
|
+
|
16
|
+
#define MARK_CONN_INACTIVE(conn) \
|
17
|
+
wrapper->active = 0
|
18
|
+
|
19
|
+
#define GET_CLIENT(self) \
|
20
|
+
mysql_client_wrapper *wrapper; \
|
21
|
+
Data_Get_Struct(self, mysql_client_wrapper, wrapper)
|
22
|
+
|
23
|
+
/*
|
24
|
+
* used to pass all arguments to mysql_real_connect while inside
|
25
|
+
* rb_thread_blocking_region
|
26
|
+
*/
|
27
|
+
struct nogvl_connect_args {
|
28
|
+
MYSQL *mysql;
|
29
|
+
const char *host;
|
30
|
+
const char *user;
|
31
|
+
const char *passwd;
|
32
|
+
const char *db;
|
33
|
+
unsigned int port;
|
34
|
+
const char *unix_socket;
|
35
|
+
unsigned long client_flag;
|
36
|
+
};
|
37
|
+
|
38
|
+
/*
|
39
|
+
* used to pass all arguments to mysql_send_query while inside
|
40
|
+
* rb_thread_blocking_region
|
41
|
+
*/
|
42
|
+
struct nogvl_send_query_args {
|
43
|
+
MYSQL *mysql;
|
44
|
+
VALUE sql;
|
45
|
+
};
|
46
|
+
|
47
|
+
/*
|
48
|
+
* non-blocking mysql_*() functions that we won't be wrapping since
|
49
|
+
* they do not appear to hit the network nor issue any interruptible
|
50
|
+
* or blocking system calls.
|
51
|
+
*
|
52
|
+
* - mysql_affected_rows()
|
53
|
+
* - mysql_error()
|
54
|
+
* - mysql_fetch_fields()
|
55
|
+
* - mysql_fetch_lengths() - calls cli_fetch_lengths or emb_fetch_lengths
|
56
|
+
* - mysql_field_count()
|
57
|
+
* - mysql_get_client_info()
|
58
|
+
* - mysql_get_client_version()
|
59
|
+
* - mysql_get_server_info()
|
60
|
+
* - mysql_get_server_version()
|
61
|
+
* - mysql_insert_id()
|
62
|
+
* - mysql_num_fields()
|
63
|
+
* - mysql_num_rows()
|
64
|
+
* - mysql_options()
|
65
|
+
* - mysql_real_escape_string()
|
66
|
+
* - mysql_ssl_set()
|
67
|
+
*/
|
68
|
+
|
69
|
+
static void rb_mysql_client_mark(void * wrapper) {
|
70
|
+
mysql_client_wrapper * w = wrapper;
|
71
|
+
if (w) {
|
72
|
+
rb_gc_mark(w->encoding);
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
static VALUE rb_raise_mysql2_error(mysql_client_wrapper *wrapper) {
|
77
|
+
VALUE rb_error_msg = rb_str_new2(mysql_error(wrapper->client));
|
78
|
+
VALUE rb_sql_state = rb_tainted_str_new2(mysql_sqlstate(wrapper->client));
|
79
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
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
|
+
}
|
89
|
+
#endif
|
90
|
+
|
91
|
+
VALUE e = rb_exc_new3(cMysql2Error, rb_error_msg);
|
92
|
+
rb_funcall(e, intern_error_number_eql, 1, UINT2NUM(mysql_errno(wrapper->client)));
|
93
|
+
rb_funcall(e, intern_sql_state_eql, 1, rb_sql_state);
|
94
|
+
rb_exc_raise(e);
|
95
|
+
return Qnil;
|
96
|
+
}
|
97
|
+
|
98
|
+
static VALUE nogvl_init(void *ptr) {
|
99
|
+
MYSQL *client;
|
100
|
+
|
101
|
+
/* may initialize embedded server and read /etc/services off disk */
|
102
|
+
client = mysql_init((MYSQL *)ptr);
|
103
|
+
return client ? Qtrue : Qfalse;
|
104
|
+
}
|
105
|
+
|
106
|
+
static VALUE nogvl_connect(void *ptr) {
|
107
|
+
struct nogvl_connect_args *args = ptr;
|
108
|
+
MYSQL *client;
|
109
|
+
|
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);
|
116
|
+
|
117
|
+
return client ? Qtrue : Qfalse;
|
118
|
+
}
|
119
|
+
|
120
|
+
static VALUE nogvl_close(void *ptr) {
|
121
|
+
mysql_client_wrapper *wrapper;
|
122
|
+
#ifndef _WIN32
|
123
|
+
int flags;
|
124
|
+
#endif
|
125
|
+
wrapper = ptr;
|
126
|
+
if (!wrapper->closed) {
|
127
|
+
wrapper->closed = 1;
|
128
|
+
|
129
|
+
/*
|
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
|
137
|
+
*/
|
138
|
+
#ifndef _WIN32
|
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);
|
146
|
+
#endif
|
147
|
+
|
148
|
+
mysql_close(wrapper->client);
|
149
|
+
xfree(wrapper->client);
|
150
|
+
}
|
151
|
+
|
152
|
+
return Qnil;
|
153
|
+
}
|
154
|
+
|
155
|
+
static void rb_mysql_client_free(void * ptr) {
|
156
|
+
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
|
157
|
+
|
158
|
+
nogvl_close(wrapper);
|
159
|
+
|
160
|
+
xfree(ptr);
|
161
|
+
}
|
162
|
+
|
163
|
+
static VALUE allocate(VALUE klass) {
|
164
|
+
VALUE obj;
|
165
|
+
mysql_client_wrapper * wrapper;
|
166
|
+
obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
|
167
|
+
wrapper->encoding = Qnil;
|
168
|
+
wrapper->active = 0;
|
169
|
+
wrapper->closed = 1;
|
170
|
+
wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
|
171
|
+
return obj;
|
172
|
+
}
|
173
|
+
|
174
|
+
static VALUE rb_mysql_client_escape(VALUE klass, VALUE str) {
|
175
|
+
unsigned char *newStr;
|
176
|
+
VALUE rb_str;
|
177
|
+
unsigned long newLen, oldLen;
|
178
|
+
|
179
|
+
Check_Type(str, T_STRING);
|
180
|
+
|
181
|
+
oldLen = RSTRING_LEN(str);
|
182
|
+
newStr = xmalloc(oldLen*2+1);
|
183
|
+
|
184
|
+
newLen = mysql_escape_string((char *)newStr, StringValuePtr(str), oldLen);
|
185
|
+
if (newLen == oldLen) {
|
186
|
+
// no need to return a new ruby string if nothing changed
|
187
|
+
xfree(newStr);
|
188
|
+
return str;
|
189
|
+
} else {
|
190
|
+
rb_str = rb_str_new((const char*)newStr, newLen);
|
191
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
192
|
+
rb_enc_copy(rb_str, str);
|
193
|
+
#endif
|
194
|
+
xfree(newStr);
|
195
|
+
return rb_str;
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags) {
|
200
|
+
struct nogvl_connect_args args;
|
201
|
+
GET_CLIENT(self);
|
202
|
+
|
203
|
+
args.host = NIL_P(host) ? "localhost" : StringValuePtr(host);
|
204
|
+
args.unix_socket = NIL_P(socket) ? NULL : StringValuePtr(socket);
|
205
|
+
args.port = NIL_P(port) ? 3306 : NUM2INT(port);
|
206
|
+
args.user = NIL_P(user) ? NULL : StringValuePtr(user);
|
207
|
+
args.passwd = NIL_P(pass) ? NULL : StringValuePtr(pass);
|
208
|
+
args.db = NIL_P(database) ? NULL : StringValuePtr(database);
|
209
|
+
args.mysql = wrapper->client;
|
210
|
+
args.client_flag = NUM2ULONG(flags);
|
211
|
+
|
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);
|
215
|
+
}
|
216
|
+
|
217
|
+
return self;
|
218
|
+
}
|
219
|
+
|
220
|
+
/*
|
221
|
+
* Immediately disconnect from the server, normally the garbage collector
|
222
|
+
* will disconnect automatically when a connection is no longer needed.
|
223
|
+
* Explicitly closing this will free up server resources sooner than waiting
|
224
|
+
* for the garbage collector.
|
225
|
+
*/
|
226
|
+
static VALUE rb_mysql_client_close(VALUE self) {
|
227
|
+
GET_CLIENT(self);
|
228
|
+
|
229
|
+
if (!wrapper->closed) {
|
230
|
+
rb_thread_blocking_region(nogvl_close, wrapper, RUBY_UBF_IO, 0);
|
231
|
+
}
|
232
|
+
|
233
|
+
return Qnil;
|
234
|
+
}
|
235
|
+
|
236
|
+
/*
|
237
|
+
* mysql_send_query is unlikely to block since most queries are small
|
238
|
+
* enough to fit in a socket buffer, but sometimes large UPDATE and
|
239
|
+
* INSERTs will cause the process to block
|
240
|
+
*/
|
241
|
+
static VALUE nogvl_send_query(void *ptr) {
|
242
|
+
struct nogvl_send_query_args *args = ptr;
|
243
|
+
int rv;
|
244
|
+
const char *sql = StringValuePtr(args->sql);
|
245
|
+
long sql_len = RSTRING_LEN(args->sql);
|
246
|
+
|
247
|
+
rv = mysql_send_query(args->mysql, sql, sql_len);
|
248
|
+
|
249
|
+
return rv == 0 ? Qtrue : Qfalse;
|
250
|
+
}
|
251
|
+
|
252
|
+
/*
|
253
|
+
* even though we did rb_thread_select before calling this, a large
|
254
|
+
* response can overflow the socket buffers and cause us to eventually
|
255
|
+
* block while calling mysql_read_query_result
|
256
|
+
*/
|
257
|
+
static VALUE nogvl_read_query_result(void *ptr) {
|
258
|
+
MYSQL * client = ptr;
|
259
|
+
my_bool res = mysql_read_query_result(client);
|
260
|
+
|
261
|
+
return res == 0 ? Qtrue : Qfalse;
|
262
|
+
}
|
263
|
+
|
264
|
+
/* mysql_store_result may (unlikely) read rows off the socket */
|
265
|
+
static VALUE nogvl_store_result(void *ptr) {
|
266
|
+
MYSQL * client = ptr;
|
267
|
+
return (VALUE)mysql_store_result(client);
|
268
|
+
}
|
269
|
+
|
270
|
+
static VALUE rb_mysql_client_async_result(VALUE self) {
|
271
|
+
MYSQL_RES * result;
|
272
|
+
VALUE resultObj;
|
273
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
274
|
+
mysql2_result_wrapper * result_wrapper;
|
275
|
+
#endif
|
276
|
+
GET_CLIENT(self);
|
277
|
+
|
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
|
281
|
+
MARK_CONN_INACTIVE(self);
|
282
|
+
return rb_raise_mysql2_error(wrapper);
|
283
|
+
}
|
284
|
+
|
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);
|
289
|
+
|
290
|
+
if (result == NULL) {
|
291
|
+
if (mysql_field_count(wrapper->client) != 0) {
|
292
|
+
rb_raise_mysql2_error(wrapper);
|
293
|
+
}
|
294
|
+
return Qnil;
|
295
|
+
}
|
296
|
+
|
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));
|
300
|
+
|
301
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
302
|
+
GetMysql2Result(resultObj, result_wrapper);
|
303
|
+
result_wrapper->encoding = wrapper->encoding;
|
304
|
+
#endif
|
305
|
+
return resultObj;
|
306
|
+
}
|
307
|
+
|
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;
|
321
|
+
GET_CLIENT(self);
|
322
|
+
|
323
|
+
REQUIRE_OPEN_DB(wrapper);
|
324
|
+
args.mysql = wrapper->client;
|
325
|
+
|
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");
|
332
|
+
}
|
333
|
+
|
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);
|
338
|
+
|
339
|
+
if (rb_hash_aref(opts, sym_async) == Qtrue) {
|
340
|
+
async = 1;
|
341
|
+
}
|
342
|
+
} else {
|
343
|
+
opts = defaults;
|
344
|
+
}
|
345
|
+
|
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
|
+
}
|
358
|
+
|
359
|
+
read_timeout = rb_iv_get(self, "@read_timeout");
|
360
|
+
|
361
|
+
tvp = NULL;
|
362
|
+
if (!NIL_P(read_timeout)) {
|
363
|
+
Check_Type(read_timeout, T_FIXNUM);
|
364
|
+
tvp = &tv;
|
365
|
+
sec = FIX2INT(read_timeout);
|
366
|
+
// TODO: support partial seconds?
|
367
|
+
// also, this check is here for sanity, we also check up in Ruby
|
368
|
+
if (sec >= 0) {
|
369
|
+
tvp->tv_sec = sec;
|
370
|
+
} else {
|
371
|
+
rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
|
372
|
+
}
|
373
|
+
tvp->tv_usec = 0;
|
374
|
+
}
|
375
|
+
|
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;
|
382
|
+
|
383
|
+
#if defined(_WIN32) && !defined(HAVE_RB_THREAD_BLOCKING_REGION) // don't need this in 1.9
|
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);
|
390
|
+
#endif
|
391
|
+
|
392
|
+
FD_ZERO(&fdset);
|
393
|
+
FD_SET(fd_set_fd, &fdset);
|
394
|
+
|
395
|
+
retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp);
|
396
|
+
|
397
|
+
#if defined(_WIN32) && !defined(HAVE_RB_THREAD_BLOCKING_REGION)
|
398
|
+
// cleanup the CRT fd
|
399
|
+
_close(fd_set_fd);
|
400
|
+
// cleanup the duplicated SOCKET
|
401
|
+
closesocket(s);
|
402
|
+
#endif
|
403
|
+
|
404
|
+
if (retval == 0) {
|
405
|
+
rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
|
406
|
+
}
|
407
|
+
|
408
|
+
if (retval < 0) {
|
409
|
+
rb_sys_fail(0);
|
410
|
+
}
|
411
|
+
|
412
|
+
if (retval > 0) {
|
413
|
+
break;
|
414
|
+
}
|
415
|
+
}
|
416
|
+
|
417
|
+
result = rb_mysql_client_async_result(self);
|
418
|
+
|
419
|
+
return result;
|
420
|
+
} else {
|
421
|
+
return Qnil;
|
422
|
+
}
|
423
|
+
}
|
424
|
+
|
425
|
+
static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
426
|
+
unsigned char *newStr;
|
427
|
+
VALUE rb_str;
|
428
|
+
unsigned long newLen, oldLen;
|
429
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
430
|
+
rb_encoding *default_internal_enc;
|
431
|
+
rb_encoding *conn_enc;
|
432
|
+
#endif
|
433
|
+
GET_CLIENT(self);
|
434
|
+
|
435
|
+
REQUIRE_OPEN_DB(wrapper);
|
436
|
+
Check_Type(str, T_STRING);
|
437
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
438
|
+
default_internal_enc = rb_default_internal_encoding();
|
439
|
+
conn_enc = rb_to_encoding(wrapper->encoding);
|
440
|
+
// ensure the string is in the encoding the connection is expecting
|
441
|
+
str = rb_str_export_to_enc(str, conn_enc);
|
442
|
+
#endif
|
443
|
+
|
444
|
+
oldLen = RSTRING_LEN(str);
|
445
|
+
newStr = xmalloc(oldLen*2+1);
|
446
|
+
|
447
|
+
newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, StringValuePtr(str), oldLen);
|
448
|
+
if (newLen == oldLen) {
|
449
|
+
// no need to return a new ruby string if nothing changed
|
450
|
+
xfree(newStr);
|
451
|
+
return str;
|
452
|
+
} else {
|
453
|
+
rb_str = rb_str_new((const char*)newStr, newLen);
|
454
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
455
|
+
rb_enc_associate(rb_str, conn_enc);
|
456
|
+
if (default_internal_enc) {
|
457
|
+
rb_str = rb_str_export_to_enc(rb_str, default_internal_enc);
|
458
|
+
}
|
459
|
+
#endif
|
460
|
+
xfree(newStr);
|
461
|
+
return rb_str;
|
462
|
+
}
|
463
|
+
}
|
464
|
+
|
465
|
+
static VALUE rb_mysql_client_info(VALUE self) {
|
466
|
+
VALUE version, client_info;
|
467
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
468
|
+
rb_encoding *default_internal_enc;
|
469
|
+
rb_encoding *conn_enc;
|
470
|
+
#endif
|
471
|
+
GET_CLIENT(self);
|
472
|
+
version = rb_hash_new();
|
473
|
+
|
474
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
475
|
+
default_internal_enc = rb_default_internal_encoding();
|
476
|
+
conn_enc = rb_to_encoding(wrapper->encoding);
|
477
|
+
#endif
|
478
|
+
|
479
|
+
rb_hash_aset(version, sym_id, LONG2NUM(mysql_get_client_version()));
|
480
|
+
client_info = rb_str_new2(mysql_get_client_info());
|
481
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
482
|
+
rb_enc_associate(client_info, conn_enc);
|
483
|
+
if (default_internal_enc) {
|
484
|
+
client_info = rb_str_export_to_enc(client_info, default_internal_enc);
|
485
|
+
}
|
486
|
+
#endif
|
487
|
+
rb_hash_aset(version, sym_version, client_info);
|
488
|
+
return version;
|
489
|
+
}
|
490
|
+
|
491
|
+
static VALUE rb_mysql_client_server_info(VALUE self) {
|
492
|
+
VALUE version, server_info;
|
493
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
494
|
+
rb_encoding *default_internal_enc;
|
495
|
+
rb_encoding *conn_enc;
|
496
|
+
#endif
|
497
|
+
GET_CLIENT(self);
|
498
|
+
|
499
|
+
REQUIRE_OPEN_DB(wrapper);
|
500
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
501
|
+
default_internal_enc = rb_default_internal_encoding();
|
502
|
+
conn_enc = rb_to_encoding(wrapper->encoding);
|
503
|
+
#endif
|
504
|
+
|
505
|
+
version = rb_hash_new();
|
506
|
+
rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
|
507
|
+
server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
|
508
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
509
|
+
rb_enc_associate(server_info, conn_enc);
|
510
|
+
if (default_internal_enc) {
|
511
|
+
server_info = rb_str_export_to_enc(server_info, default_internal_enc);
|
512
|
+
}
|
513
|
+
#endif
|
514
|
+
rb_hash_aset(version, sym_version, server_info);
|
515
|
+
return version;
|
516
|
+
}
|
517
|
+
|
518
|
+
static VALUE rb_mysql_client_socket(VALUE self) {
|
519
|
+
GET_CLIENT(self);
|
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);
|
530
|
+
#else
|
531
|
+
return INT2NUM(fd_set_fd);
|
532
|
+
#endif
|
533
|
+
}
|
534
|
+
|
535
|
+
static VALUE rb_mysql_client_last_id(VALUE self) {
|
536
|
+
GET_CLIENT(self);
|
537
|
+
REQUIRE_OPEN_DB(wrapper);
|
538
|
+
return ULL2NUM(mysql_insert_id(wrapper->client));
|
539
|
+
}
|
540
|
+
|
541
|
+
static VALUE rb_mysql_client_affected_rows(VALUE self) {
|
542
|
+
my_ulonglong retVal;
|
543
|
+
GET_CLIENT(self);
|
544
|
+
|
545
|
+
REQUIRE_OPEN_DB(wrapper);
|
546
|
+
retVal = mysql_affected_rows(wrapper->client);
|
547
|
+
if (retVal == (my_ulonglong)-1) {
|
548
|
+
rb_raise_mysql2_error(wrapper);
|
549
|
+
}
|
550
|
+
return ULL2NUM(retVal);
|
551
|
+
}
|
552
|
+
|
553
|
+
static VALUE rb_mysql_client_thread_id(VALUE self) {
|
554
|
+
unsigned long retVal;
|
555
|
+
GET_CLIENT(self);
|
556
|
+
|
557
|
+
REQUIRE_OPEN_DB(wrapper);
|
558
|
+
retVal = mysql_thread_id(wrapper->client);
|
559
|
+
return ULL2NUM(retVal);
|
560
|
+
}
|
561
|
+
|
562
|
+
static VALUE nogvl_ping(void *ptr)
|
563
|
+
{
|
564
|
+
MYSQL *client = ptr;
|
565
|
+
|
566
|
+
return mysql_ping(client) == 0 ? Qtrue : Qfalse;
|
567
|
+
}
|
568
|
+
|
569
|
+
static VALUE rb_mysql_client_ping(VALUE self) {
|
570
|
+
GET_CLIENT(self);
|
571
|
+
|
572
|
+
if (wrapper->closed) {
|
573
|
+
return Qfalse;
|
574
|
+
} else {
|
575
|
+
return rb_thread_blocking_region(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
|
576
|
+
}
|
577
|
+
}
|
578
|
+
|
579
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
580
|
+
static VALUE rb_mysql_client_encoding(VALUE self) {
|
581
|
+
GET_CLIENT(self);
|
582
|
+
return wrapper->encoding;
|
583
|
+
}
|
584
|
+
#endif
|
585
|
+
|
586
|
+
static VALUE set_reconnect(VALUE self, VALUE value) {
|
587
|
+
my_bool reconnect;
|
588
|
+
GET_CLIENT(self);
|
589
|
+
|
590
|
+
if(!NIL_P(value)) {
|
591
|
+
reconnect = value == Qfalse ? 0 : 1;
|
592
|
+
|
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
|
+
}
|
598
|
+
}
|
599
|
+
return value;
|
600
|
+
}
|
601
|
+
|
602
|
+
static VALUE set_connect_timeout(VALUE self, VALUE value) {
|
603
|
+
unsigned int connect_timeout = 0;
|
604
|
+
GET_CLIENT(self);
|
605
|
+
|
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
|
+
}
|
615
|
+
}
|
616
|
+
return value;
|
617
|
+
}
|
618
|
+
|
619
|
+
static VALUE set_charset_name(VALUE self, VALUE value) {
|
620
|
+
char * charset_name;
|
621
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
622
|
+
VALUE new_encoding;
|
623
|
+
#endif
|
624
|
+
GET_CLIENT(self);
|
625
|
+
|
626
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
627
|
+
new_encoding = rb_funcall(cMysql2Client, intern_encoding_from_charset, 1, value);
|
628
|
+
if (new_encoding == Qnil) {
|
629
|
+
VALUE inspect = rb_inspect(value);
|
630
|
+
rb_raise(cMysql2Error, "Unsupported charset: '%s'", RSTRING_PTR(inspect));
|
631
|
+
} else {
|
632
|
+
if (wrapper->encoding == Qnil) {
|
633
|
+
wrapper->encoding = new_encoding;
|
634
|
+
}
|
635
|
+
}
|
636
|
+
#endif
|
637
|
+
|
638
|
+
charset_name = StringValuePtr(value);
|
639
|
+
|
640
|
+
if (mysql_options(wrapper->client, MYSQL_SET_CHARSET_NAME, charset_name)) {
|
641
|
+
/* TODO: warning - unable to set charset */
|
642
|
+
rb_warn("%s\n", mysql_error(wrapper->client));
|
643
|
+
}
|
644
|
+
|
645
|
+
return value;
|
646
|
+
}
|
647
|
+
|
648
|
+
static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE capath, VALUE cipher) {
|
649
|
+
GET_CLIENT(self);
|
650
|
+
|
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
|
+
}
|
659
|
+
|
660
|
+
return self;
|
661
|
+
}
|
662
|
+
|
663
|
+
static VALUE init_connection(VALUE self) {
|
664
|
+
GET_CLIENT(self);
|
665
|
+
|
666
|
+
if (rb_thread_blocking_region(nogvl_init, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
|
667
|
+
/* TODO: warning - not enough memory? */
|
668
|
+
return rb_raise_mysql2_error(wrapper);
|
669
|
+
}
|
670
|
+
|
671
|
+
wrapper->closed = 0;
|
672
|
+
return self;
|
673
|
+
}
|
674
|
+
|
675
|
+
void init_mysql2_client() {
|
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
|
678
|
+
int i;
|
679
|
+
int dots = 0;
|
680
|
+
const char *lib = mysql_get_client_info();
|
681
|
+
for (i = 0; lib[i] != 0 && MYSQL_SERVER_VERSION[i] != 0; i++) {
|
682
|
+
if (lib[i] == '.') {
|
683
|
+
dots++;
|
684
|
+
// we only compare MAJOR and MINOR
|
685
|
+
if (dots == 2) break;
|
686
|
+
}
|
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);
|
689
|
+
return;
|
690
|
+
}
|
691
|
+
}
|
692
|
+
|
693
|
+
cMysql2Client = rb_define_class_under(mMysql2, "Client", rb_cObject);
|
694
|
+
|
695
|
+
rb_define_alloc_func(cMysql2Client, allocate);
|
696
|
+
|
697
|
+
rb_define_singleton_method(cMysql2Client, "escape", rb_mysql_client_escape, 1);
|
698
|
+
|
699
|
+
rb_define_method(cMysql2Client, "close", rb_mysql_client_close, 0);
|
700
|
+
rb_define_method(cMysql2Client, "query", rb_mysql_client_query, -1);
|
701
|
+
rb_define_method(cMysql2Client, "escape", rb_mysql_client_real_escape, 1);
|
702
|
+
rb_define_method(cMysql2Client, "info", rb_mysql_client_info, 0);
|
703
|
+
rb_define_method(cMysql2Client, "server_info", rb_mysql_client_server_info, 0);
|
704
|
+
rb_define_method(cMysql2Client, "socket", rb_mysql_client_socket, 0);
|
705
|
+
rb_define_method(cMysql2Client, "async_result", rb_mysql_client_async_result, 0);
|
706
|
+
rb_define_method(cMysql2Client, "last_id", rb_mysql_client_last_id, 0);
|
707
|
+
rb_define_method(cMysql2Client, "affected_rows", rb_mysql_client_affected_rows, 0);
|
708
|
+
rb_define_method(cMysql2Client, "thread_id", rb_mysql_client_thread_id, 0);
|
709
|
+
rb_define_method(cMysql2Client, "ping", rb_mysql_client_ping, 0);
|
710
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
711
|
+
rb_define_method(cMysql2Client, "encoding", rb_mysql_client_encoding, 0);
|
712
|
+
#endif
|
713
|
+
|
714
|
+
rb_define_private_method(cMysql2Client, "reconnect=", set_reconnect, 1);
|
715
|
+
rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
|
716
|
+
rb_define_private_method(cMysql2Client, "charset_name=", set_charset_name, 1);
|
717
|
+
rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
|
718
|
+
rb_define_private_method(cMysql2Client, "init_connection", init_connection, 0);
|
719
|
+
rb_define_private_method(cMysql2Client, "connect", rb_connect, 7);
|
720
|
+
|
721
|
+
intern_encoding_from_charset = rb_intern("encoding_from_charset");
|
722
|
+
|
723
|
+
sym_id = ID2SYM(rb_intern("id"));
|
724
|
+
sym_version = ID2SYM(rb_intern("version"));
|
725
|
+
sym_async = ID2SYM(rb_intern("async"));
|
726
|
+
sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
|
727
|
+
sym_as = ID2SYM(rb_intern("as"));
|
728
|
+
sym_array = ID2SYM(rb_intern("array"));
|
729
|
+
|
730
|
+
intern_merge = rb_intern("merge");
|
731
|
+
intern_error_number_eql = rb_intern("error_number=");
|
732
|
+
intern_sql_state_eql = rb_intern("sql_state=");
|
733
|
+
|
734
|
+
#ifdef CLIENT_LONG_PASSWORD
|
735
|
+
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
|
736
|
+
INT2NUM(CLIENT_LONG_PASSWORD));
|
737
|
+
#endif
|
738
|
+
|
739
|
+
#ifdef CLIENT_FOUND_ROWS
|
740
|
+
rb_const_set(cMysql2Client, rb_intern("FOUND_ROWS"),
|
741
|
+
INT2NUM(CLIENT_FOUND_ROWS));
|
742
|
+
#endif
|
743
|
+
|
744
|
+
#ifdef CLIENT_LONG_FLAG
|
745
|
+
rb_const_set(cMysql2Client, rb_intern("LONG_FLAG"),
|
746
|
+
INT2NUM(CLIENT_LONG_FLAG));
|
747
|
+
#endif
|
748
|
+
|
749
|
+
#ifdef CLIENT_CONNECT_WITH_DB
|
750
|
+
rb_const_set(cMysql2Client, rb_intern("CONNECT_WITH_DB"),
|
751
|
+
INT2NUM(CLIENT_CONNECT_WITH_DB));
|
752
|
+
#endif
|
753
|
+
|
754
|
+
#ifdef CLIENT_NO_SCHEMA
|
755
|
+
rb_const_set(cMysql2Client, rb_intern("NO_SCHEMA"),
|
756
|
+
INT2NUM(CLIENT_NO_SCHEMA));
|
757
|
+
#endif
|
758
|
+
|
759
|
+
#ifdef CLIENT_COMPRESS
|
760
|
+
rb_const_set(cMysql2Client, rb_intern("COMPRESS"), INT2NUM(CLIENT_COMPRESS));
|
761
|
+
#endif
|
762
|
+
|
763
|
+
#ifdef CLIENT_ODBC
|
764
|
+
rb_const_set(cMysql2Client, rb_intern("ODBC"), INT2NUM(CLIENT_ODBC));
|
765
|
+
#endif
|
766
|
+
|
767
|
+
#ifdef CLIENT_LOCAL_FILES
|
768
|
+
rb_const_set(cMysql2Client, rb_intern("LOCAL_FILES"),
|
769
|
+
INT2NUM(CLIENT_LOCAL_FILES));
|
770
|
+
#endif
|
771
|
+
|
772
|
+
#ifdef CLIENT_IGNORE_SPACE
|
773
|
+
rb_const_set(cMysql2Client, rb_intern("IGNORE_SPACE"),
|
774
|
+
INT2NUM(CLIENT_IGNORE_SPACE));
|
775
|
+
#endif
|
776
|
+
|
777
|
+
#ifdef CLIENT_PROTOCOL_41
|
778
|
+
rb_const_set(cMysql2Client, rb_intern("PROTOCOL_41"),
|
779
|
+
INT2NUM(CLIENT_PROTOCOL_41));
|
780
|
+
#endif
|
781
|
+
|
782
|
+
#ifdef CLIENT_INTERACTIVE
|
783
|
+
rb_const_set(cMysql2Client, rb_intern("INTERACTIVE"),
|
784
|
+
INT2NUM(CLIENT_INTERACTIVE));
|
785
|
+
#endif
|
786
|
+
|
787
|
+
#ifdef CLIENT_SSL
|
788
|
+
rb_const_set(cMysql2Client, rb_intern("SSL"), INT2NUM(CLIENT_SSL));
|
789
|
+
#endif
|
790
|
+
|
791
|
+
#ifdef CLIENT_IGNORE_SIGPIPE
|
792
|
+
rb_const_set(cMysql2Client, rb_intern("IGNORE_SIGPIPE"),
|
793
|
+
INT2NUM(CLIENT_IGNORE_SIGPIPE));
|
794
|
+
#endif
|
795
|
+
|
796
|
+
#ifdef CLIENT_TRANSACTIONS
|
797
|
+
rb_const_set(cMysql2Client, rb_intern("TRANSACTIONS"),
|
798
|
+
INT2NUM(CLIENT_TRANSACTIONS));
|
799
|
+
#endif
|
800
|
+
|
801
|
+
#ifdef CLIENT_RESERVED
|
802
|
+
rb_const_set(cMysql2Client, rb_intern("RESERVED"), INT2NUM(CLIENT_RESERVED));
|
803
|
+
#endif
|
804
|
+
|
805
|
+
#ifdef CLIENT_SECURE_CONNECTION
|
806
|
+
rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"),
|
807
|
+
INT2NUM(CLIENT_SECURE_CONNECTION));
|
808
|
+
#endif
|
809
|
+
|
810
|
+
#ifdef CLIENT_MULTI_STATEMENTS
|
811
|
+
rb_const_set(cMysql2Client, rb_intern("MULTI_STATEMENTS"),
|
812
|
+
INT2NUM(CLIENT_MULTI_STATEMENTS));
|
813
|
+
#endif
|
814
|
+
|
815
|
+
#ifdef CLIENT_PS_MULTI_RESULTS
|
816
|
+
rb_const_set(cMysql2Client, rb_intern("PS_MULTI_RESULTS"),
|
817
|
+
INT2NUM(CLIENT_PS_MULTI_RESULTS));
|
818
|
+
#endif
|
819
|
+
|
820
|
+
#ifdef CLIENT_SSL_VERIFY_SERVER_CERT
|
821
|
+
rb_const_set(cMysql2Client, rb_intern("SSL_VERIFY_SERVER_CERT"),
|
822
|
+
INT2NUM(CLIENT_SSL_VERIFY_SERVER_CERT));
|
823
|
+
#endif
|
824
|
+
|
825
|
+
#ifdef CLIENT_REMEMBER_OPTIONS
|
826
|
+
rb_const_set(cMysql2Client, rb_intern("REMEMBER_OPTIONS"),
|
827
|
+
INT2NUM(CLIENT_REMEMBER_OPTIONS));
|
828
|
+
#endif
|
829
|
+
|
830
|
+
#ifdef CLIENT_ALL_FLAGS
|
831
|
+
rb_const_set(cMysql2Client, rb_intern("ALL_FLAGS"),
|
832
|
+
INT2NUM(CLIENT_ALL_FLAGS));
|
833
|
+
#endif
|
834
|
+
|
835
|
+
#ifdef CLIENT_BASIC_FLAGS
|
836
|
+
rb_const_set(cMysql2Client, rb_intern("BASIC_FLAGS"),
|
837
|
+
INT2NUM(CLIENT_BASIC_FLAGS));
|
838
|
+
#endif
|
839
|
+
}
|