mysql2 0.2.6-x86-mingw32 → 0.2.16-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/CHANGELOG.md +60 -1
- data/Gemfile +3 -0
- data/MIT-LICENSE +1 -1
- data/README.md +326 -0
- data/benchmark/active_record.rb +2 -4
- data/benchmark/active_record_threaded.rb +42 -0
- data/benchmark/escape.rb +3 -6
- data/benchmark/query_with_mysql_casting.rb +3 -6
- data/benchmark/query_without_mysql_casting.rb +13 -7
- data/benchmark/sequel.rb +4 -6
- data/benchmark/setup_db.rb +17 -13
- data/benchmark/threaded.rb +44 -0
- data/ext/mysql2/client.c +314 -80
- data/ext/mysql2/client.h +3 -2
- data/ext/mysql2/extconf.rb +9 -1
- data/ext/mysql2/mysql2_ext.h +10 -0
- data/ext/mysql2/result.c +128 -37
- data/ext/mysql2/result.h +2 -2
- data/ext/mysql2/wait_for_single_fd.h +36 -0
- data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +10 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +9 -58
- data/lib/active_record/fiber_patches.rb +37 -9
- data/lib/mysql2.rb +7 -2
- data/lib/mysql2/client.rb +9 -2
- data/lib/mysql2/em.rb +10 -6
- data/lib/mysql2/em_fiber.rb +31 -0
- data/lib/mysql2/version.rb +3 -0
- data/mysql2.gemspec +18 -78
- data/spec/em/em_fiber_spec.rb +22 -0
- data/spec/mysql2/client_spec.rb +179 -62
- data/spec/mysql2/error_spec.rb +47 -3
- data/spec/mysql2/result_spec.rb +78 -8
- data/spec/spec_helper.rb +2 -2
- data/tasks/benchmarks.rake +15 -3
- data/tasks/compile.rake +23 -6
- data/tasks/vendor_mysql.rake +6 -7
- metadata +145 -48
- data/README.rdoc +0 -240
- data/VERSION +0 -1
- data/tasks/jeweler.rake +0 -17
data/ext/mysql2/client.h
CHANGED
data/ext/mysql2/extconf.rb
CHANGED
@@ -7,6 +7,7 @@ end
|
|
7
7
|
|
8
8
|
# 1.9-only
|
9
9
|
have_func('rb_thread_blocking_region')
|
10
|
+
have_func('rb_wait_for_single_fd')
|
10
11
|
|
11
12
|
# borrowed from mysqlplus
|
12
13
|
# http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb
|
@@ -31,7 +32,10 @@ elsif mc = (with_config('mysql-config') || Dir[GLOB].first) then
|
|
31
32
|
mc = Dir[GLOB].first if mc == true
|
32
33
|
cflags = `#{mc} --cflags`.chomp
|
33
34
|
exit 1 if $? != 0
|
34
|
-
libs = `#{mc} --
|
35
|
+
libs = `#{mc} --libs_r`.chomp
|
36
|
+
if libs.empty?
|
37
|
+
libs = `#{mc} --libs`.chomp
|
38
|
+
end
|
35
39
|
exit 1 if $? != 0
|
36
40
|
$CPPFLAGS += ' ' + cflags
|
37
41
|
$libs = libs + " " + $libs
|
@@ -62,4 +66,8 @@ unless RUBY_PLATFORM =~ /mswin/ or RUBY_PLATFORM =~ /sparc/
|
|
62
66
|
end
|
63
67
|
# $CFLAGS << ' -O0 -ggdb3 -Wextra'
|
64
68
|
|
69
|
+
if hard_mysql_path = $libs[%r{-L(/[^ ]+)}, 1]
|
70
|
+
$LDFLAGS << " -Wl,-rpath,#{hard_mysql_path}"
|
71
|
+
end
|
72
|
+
|
65
73
|
create_makefile('mysql2/mysql2')
|
data/ext/mysql2/mysql2_ext.h
CHANGED
@@ -1,9 +1,19 @@
|
|
1
1
|
#ifndef MYSQL2_EXT
|
2
2
|
#define MYSQL2_EXT
|
3
3
|
|
4
|
+
// tell rbx not to use it's caching compat layer
|
5
|
+
// by doing this we're making a promize to RBX that
|
6
|
+
// we'll never modify the pointers we get back from RSTRING_PTR
|
7
|
+
#define RSTRING_NOT_MODIFIED
|
4
8
|
#include <ruby.h>
|
5
9
|
#include <fcntl.h>
|
6
10
|
|
11
|
+
#ifndef HAVE_UINT
|
12
|
+
#define HAVE_UINT
|
13
|
+
typedef unsigned short ushort;
|
14
|
+
typedef unsigned int uint;
|
15
|
+
#endif
|
16
|
+
|
7
17
|
#ifdef HAVE_MYSQL_H
|
8
18
|
#include <mysql.h>
|
9
19
|
#include <mysql_com.h>
|
data/ext/mysql2/result.c
CHANGED
@@ -1,18 +1,61 @@
|
|
1
1
|
#include <mysql2_ext.h>
|
2
|
+
#include <stdint.h>
|
2
3
|
|
3
4
|
#ifdef HAVE_RUBY_ENCODING_H
|
4
|
-
rb_encoding *binaryEncoding;
|
5
|
+
static rb_encoding *binaryEncoding;
|
5
6
|
#endif
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
#if (SIZEOF_INT < SIZEOF_LONG) || defined(HAVE_RUBY_ENCODING_H)
|
9
|
+
/* on 64bit platforms we can handle dates way outside 2038-01-19T03:14:07
|
10
|
+
*
|
11
|
+
* (9999*31557600) + (12*2592000) + (31*86400) + (11*3600) + (59*60) + 59
|
12
|
+
*/
|
13
|
+
#define MYSQL2_MAX_TIME 315578267999ULL
|
14
|
+
#else
|
15
|
+
/**
|
16
|
+
* On 32bit platforms the maximum date the Time class can handle is 2038-01-19T03:14:07
|
17
|
+
* 2038 years + 1 month + 19 days + 3 hours + 14 minutes + 7 seconds = 64318634047 seconds
|
18
|
+
*
|
19
|
+
* (2038*31557600) + (1*2592000) + (19*86400) + (3*3600) + (14*60) + 7
|
20
|
+
*/
|
21
|
+
#define MYSQL2_MAX_TIME 64318634047ULL
|
22
|
+
#endif
|
23
|
+
|
24
|
+
#if defined(HAVE_RUBY_ENCODING_H)
|
25
|
+
/* 0000-1-1 00:00:00 UTC
|
26
|
+
*
|
27
|
+
* (0*31557600) + (1*2592000) + (1*86400) + (0*3600) + (0*60) + 0
|
28
|
+
*/
|
29
|
+
#define MYSQL2_MIN_TIME 2678400ULL
|
30
|
+
#elif SIZEOF_INT < SIZEOF_LONG // 64bit Ruby 1.8
|
31
|
+
/* 0139-1-1 00:00:00 UTC
|
32
|
+
*
|
33
|
+
* (139*31557600) + (1*2592000) + (1*86400) + (0*3600) + (0*60) + 0
|
34
|
+
*/
|
35
|
+
#define MYSQL2_MIN_TIME 4389184800ULL
|
36
|
+
#elif defined(NEGATIVE_TIME_T)
|
37
|
+
/* 1901-12-13 20:45:52 UTC : The oldest time in 32-bit signed time_t.
|
38
|
+
*
|
39
|
+
* (1901*31557600) + (12*2592000) + (13*86400) + (20*3600) + (45*60) + 52
|
40
|
+
*/
|
41
|
+
#define MYSQL2_MIN_TIME 60023299552ULL
|
42
|
+
#else
|
43
|
+
/* 1970-01-01 00:00:01 UTC : The Unix epoch - the oldest time in portable time_t.
|
44
|
+
*
|
45
|
+
* (1970*31557600) + (1*2592000) + (1*86400) + (0*3600) + (0*60) + 1
|
46
|
+
*/
|
47
|
+
#define MYSQL2_MIN_TIME 62171150401ULL
|
48
|
+
#endif
|
49
|
+
|
50
|
+
static VALUE cMysql2Result;
|
51
|
+
static VALUE cBigDecimal, cDate, cDateTime;
|
52
|
+
static VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month, opt_utc_offset;
|
10
53
|
extern VALUE mMysql2, cMysql2Client, cMysql2Error;
|
11
54
|
static VALUE intern_encoding_from_charset;
|
12
55
|
static ID intern_new, intern_utc, intern_local, intern_encoding_from_charset_code,
|
13
56
|
intern_localtime, intern_local_offset, intern_civil, intern_new_offset;
|
14
|
-
static
|
15
|
-
sym_local, sym_utc, sym_cast_booleans, sym_cache_rows;
|
57
|
+
static VALUE sym_symbolize_keys, sym_as, sym_array, sym_database_timezone, sym_application_timezone,
|
58
|
+
sym_local, sym_utc, sym_cast_booleans, sym_cache_rows, sym_cast;
|
16
59
|
static ID intern_merge;
|
17
60
|
|
18
61
|
static void rb_mysql_result_mark(void * wrapper) {
|
@@ -53,7 +96,7 @@ static VALUE nogvl_fetch_row(void *ptr) {
|
|
53
96
|
|
54
97
|
static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int symbolize_keys) {
|
55
98
|
mysql2_result_wrapper * wrapper;
|
56
|
-
|
99
|
+
VALUE rb_field;
|
57
100
|
GetMysql2Result(self, wrapper);
|
58
101
|
|
59
102
|
if (wrapper->fields == Qnil) {
|
@@ -61,7 +104,7 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int
|
|
61
104
|
wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
|
62
105
|
}
|
63
106
|
|
64
|
-
|
107
|
+
rb_field = rb_ary_entry(wrapper->fields, idx);
|
65
108
|
if (rb_field == Qnil) {
|
66
109
|
MYSQL_FIELD *field = NULL;
|
67
110
|
#ifdef HAVE_RUBY_ENCODING_H
|
@@ -71,10 +114,15 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int
|
|
71
114
|
|
72
115
|
field = mysql_fetch_field_direct(wrapper->result, idx);
|
73
116
|
if (symbolize_keys) {
|
117
|
+
VALUE colStr;
|
74
118
|
char buf[field->name_length+1];
|
75
119
|
memcpy(buf, field->name, field->name_length);
|
76
120
|
buf[field->name_length] = 0;
|
77
|
-
|
121
|
+
colStr = rb_str_new2(buf);
|
122
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
123
|
+
rb_enc_associate(colStr, rb_utf8_encoding());
|
124
|
+
#endif
|
125
|
+
rb_field = ID2SYM(rb_to_id(colStr));
|
78
126
|
} else {
|
79
127
|
rb_field = rb_str_new(field->name, field->name_length);
|
80
128
|
#ifdef HAVE_RUBY_ENCODING_H
|
@@ -90,7 +138,32 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int
|
|
90
138
|
return rb_field;
|
91
139
|
}
|
92
140
|
|
93
|
-
|
141
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
142
|
+
static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_encoding *default_internal_enc, rb_encoding *conn_enc) {
|
143
|
+
// if binary flag is set, respect it's wishes
|
144
|
+
if (field.flags & BINARY_FLAG && field.charsetnr == 63) {
|
145
|
+
rb_enc_associate(val, binaryEncoding);
|
146
|
+
} else {
|
147
|
+
// lookup the encoding configured on this field
|
148
|
+
VALUE new_encoding = rb_funcall(cMysql2Client, intern_encoding_from_charset_code, 1, INT2NUM(field.charsetnr));
|
149
|
+
if (new_encoding != Qnil) {
|
150
|
+
// use the field encoding we were able to match
|
151
|
+
rb_encoding *enc = rb_to_encoding(new_encoding);
|
152
|
+
rb_enc_associate(val, enc);
|
153
|
+
} else {
|
154
|
+
// otherwise fall-back to the connection's encoding
|
155
|
+
rb_enc_associate(val, conn_enc);
|
156
|
+
}
|
157
|
+
if (default_internal_enc) {
|
158
|
+
val = rb_str_export_to_enc(val, default_internal_enc);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
return val;
|
162
|
+
}
|
163
|
+
#endif
|
164
|
+
|
165
|
+
|
166
|
+
static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezone, int symbolizeKeys, int asArray, int castBool, int cast) {
|
94
167
|
VALUE rowVal;
|
95
168
|
mysql2_result_wrapper * wrapper;
|
96
169
|
MYSQL_ROW row;
|
@@ -98,12 +171,15 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
98
171
|
unsigned int i = 0;
|
99
172
|
unsigned long * fieldLengths;
|
100
173
|
void * ptr;
|
101
|
-
|
174
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
175
|
+
rb_encoding *default_internal_enc;
|
176
|
+
rb_encoding *conn_enc;
|
177
|
+
#endif
|
102
178
|
GetMysql2Result(self, wrapper);
|
103
179
|
|
104
180
|
#ifdef HAVE_RUBY_ENCODING_H
|
105
|
-
|
106
|
-
|
181
|
+
default_internal_enc = rb_default_internal_encoding();
|
182
|
+
conn_enc = rb_to_encoding(wrapper->encoding);
|
107
183
|
#endif
|
108
184
|
|
109
185
|
ptr = wrapper->result;
|
@@ -128,7 +204,19 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
128
204
|
VALUE field = rb_mysql_result_fetch_field(self, i, symbolizeKeys);
|
129
205
|
if (row[i]) {
|
130
206
|
VALUE val = Qnil;
|
131
|
-
|
207
|
+
enum enum_field_types type = fields[i].type;
|
208
|
+
|
209
|
+
if(!cast) {
|
210
|
+
if (type == MYSQL_TYPE_NULL) {
|
211
|
+
val = Qnil;
|
212
|
+
} else {
|
213
|
+
val = rb_str_new(row[i], fieldLengths[i]);
|
214
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
215
|
+
val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
|
216
|
+
#endif
|
217
|
+
}
|
218
|
+
} else {
|
219
|
+
switch(type) {
|
132
220
|
case MYSQL_TYPE_NULL: // NULL-type field
|
133
221
|
val = Qnil;
|
134
222
|
break;
|
@@ -181,16 +269,20 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
181
269
|
}
|
182
270
|
case MYSQL_TYPE_TIMESTAMP: // TIMESTAMP field
|
183
271
|
case MYSQL_TYPE_DATETIME: { // DATETIME field
|
184
|
-
int year, month, day, hour, min, sec, tokens;
|
272
|
+
unsigned int year, month, day, hour, min, sec, tokens;
|
273
|
+
uint64_t seconds;
|
274
|
+
|
185
275
|
tokens = sscanf(row[i], "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
|
186
|
-
|
276
|
+
seconds = (year*31557600ULL) + (month*2592000ULL) + (day*86400ULL) + (hour*3600ULL) + (min*60ULL) + sec;
|
277
|
+
|
278
|
+
if (seconds == 0) {
|
187
279
|
val = Qnil;
|
188
280
|
} else {
|
189
281
|
if (month < 1 || day < 1) {
|
190
282
|
rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
|
191
283
|
val = Qnil;
|
192
284
|
} else {
|
193
|
-
if (
|
285
|
+
if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) { // use DateTime instead
|
194
286
|
VALUE offset = INT2NUM(0);
|
195
287
|
if (db_timezone == intern_local) {
|
196
288
|
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
|
@@ -247,26 +339,10 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
247
339
|
default:
|
248
340
|
val = rb_str_new(row[i], fieldLengths[i]);
|
249
341
|
#ifdef HAVE_RUBY_ENCODING_H
|
250
|
-
|
251
|
-
if (fields[i].flags & BINARY_FLAG) {
|
252
|
-
rb_enc_associate(val, binaryEncoding);
|
253
|
-
} else {
|
254
|
-
// lookup the encoding configured on this field
|
255
|
-
VALUE new_encoding = rb_funcall(cMysql2Client, intern_encoding_from_charset_code, 1, INT2NUM(fields[i].charsetnr));
|
256
|
-
if (new_encoding != Qnil) {
|
257
|
-
// use the field encoding we were able to match
|
258
|
-
rb_encoding *enc = rb_to_encoding(new_encoding);
|
259
|
-
rb_enc_associate(val, enc);
|
260
|
-
} else {
|
261
|
-
// otherwise fall-back to the connection's encoding
|
262
|
-
rb_enc_associate(val, conn_enc);
|
263
|
-
}
|
264
|
-
if (default_internal_enc) {
|
265
|
-
val = rb_str_export_to_enc(val, default_internal_enc);
|
266
|
-
}
|
267
|
-
}
|
342
|
+
val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
|
268
343
|
#endif
|
269
344
|
break;
|
345
|
+
}
|
270
346
|
}
|
271
347
|
if (asArray) {
|
272
348
|
rb_ary_push(rowVal, val);
|
@@ -316,7 +392,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
316
392
|
ID db_timezone, app_timezone, dbTz, appTz;
|
317
393
|
mysql2_result_wrapper * wrapper;
|
318
394
|
unsigned long i;
|
319
|
-
int symbolizeKeys = 0, asArray = 0, castBool = 0, cacheRows = 1;
|
395
|
+
int symbolizeKeys = 0, asArray = 0, castBool = 0, cacheRows = 1, cast = 1;
|
320
396
|
|
321
397
|
GetMysql2Result(self, wrapper);
|
322
398
|
|
@@ -343,6 +419,10 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
343
419
|
cacheRows = 0;
|
344
420
|
}
|
345
421
|
|
422
|
+
if (rb_hash_aref(opts, sym_cast) == Qfalse) {
|
423
|
+
cast = 0;
|
424
|
+
}
|
425
|
+
|
346
426
|
dbTz = rb_hash_aref(opts, sym_database_timezone);
|
347
427
|
if (dbTz == sym_local) {
|
348
428
|
db_timezone = intern_local;
|
@@ -387,7 +467,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
387
467
|
if (cacheRows && i < rowsProcessed) {
|
388
468
|
row = rb_ary_entry(wrapper->rows, i);
|
389
469
|
} else {
|
390
|
-
row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool);
|
470
|
+
row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool, cast);
|
391
471
|
if (cacheRows) {
|
392
472
|
rb_ary_store(wrapper->rows, i, row);
|
393
473
|
}
|
@@ -413,6 +493,14 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
413
493
|
return wrapper->rows;
|
414
494
|
}
|
415
495
|
|
496
|
+
static VALUE rb_mysql_result_count(VALUE self) {
|
497
|
+
mysql2_result_wrapper *wrapper;
|
498
|
+
|
499
|
+
GetMysql2Result(self, wrapper);
|
500
|
+
|
501
|
+
return INT2FIX(mysql_num_rows(wrapper->result));
|
502
|
+
}
|
503
|
+
|
416
504
|
/* Mysql2::Result */
|
417
505
|
VALUE rb_mysql_result_to_obj(MYSQL_RES * r) {
|
418
506
|
VALUE obj;
|
@@ -438,6 +526,8 @@ void init_mysql2_result() {
|
|
438
526
|
cMysql2Result = rb_define_class_under(mMysql2, "Result", rb_cObject);
|
439
527
|
rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1);
|
440
528
|
rb_define_method(cMysql2Result, "fields", rb_mysql_result_fetch_fields, 0);
|
529
|
+
rb_define_method(cMysql2Result, "count", rb_mysql_result_count, 0);
|
530
|
+
rb_define_alias(cMysql2Result, "size", "count");
|
441
531
|
|
442
532
|
intern_encoding_from_charset = rb_intern("encoding_from_charset");
|
443
533
|
intern_encoding_from_charset_code = rb_intern("encoding_from_charset_code");
|
@@ -460,6 +550,7 @@ void init_mysql2_result() {
|
|
460
550
|
sym_database_timezone = ID2SYM(rb_intern("database_timezone"));
|
461
551
|
sym_application_timezone = ID2SYM(rb_intern("application_timezone"));
|
462
552
|
sym_cache_rows = ID2SYM(rb_intern("cache_rows"));
|
553
|
+
sym_cast = ID2SYM(rb_intern("cast"));
|
463
554
|
|
464
555
|
opt_decimal_zero = rb_str_new2("0.0");
|
465
556
|
rb_global_variable(&opt_decimal_zero); //never GC
|
data/ext/mysql2/result.h
CHANGED
@@ -8,10 +8,10 @@ typedef struct {
|
|
8
8
|
VALUE fields;
|
9
9
|
VALUE rows;
|
10
10
|
VALUE encoding;
|
11
|
-
|
11
|
+
unsigned int numberOfFields;
|
12
12
|
unsigned long numberOfRows;
|
13
13
|
unsigned long lastRowProcessed;
|
14
|
-
|
14
|
+
char resultFreed;
|
15
15
|
MYSQL_RES *result;
|
16
16
|
} mysql2_result_wrapper;
|
17
17
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
/*
|
2
|
+
* backwards compatibility for pre-1.9.3 C API
|
3
|
+
*
|
4
|
+
* Ruby 1.9.3 provides this API which allows the use of ppoll() on Linux
|
5
|
+
* to minimize select() and malloc() overhead on high-numbered FDs.
|
6
|
+
*/
|
7
|
+
#ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
|
8
|
+
# include <ruby/io.h>
|
9
|
+
#else
|
10
|
+
# define RB_WAITFD_IN 0x001
|
11
|
+
# define RB_WAITFD_PRI 0x002
|
12
|
+
# define RB_WAITFD_OUT 0x004
|
13
|
+
|
14
|
+
static int my_wait_for_single_fd(int fd, int events, struct timeval *tvp)
|
15
|
+
{
|
16
|
+
fd_set fdset;
|
17
|
+
fd_set *rfds = NULL;
|
18
|
+
fd_set *wfds = NULL;
|
19
|
+
fd_set *efds = NULL;
|
20
|
+
|
21
|
+
FD_ZERO(&fdset);
|
22
|
+
FD_SET(fd, &fdset);
|
23
|
+
|
24
|
+
if (events & RB_WAITFD_IN)
|
25
|
+
rfds = &fdset;
|
26
|
+
if (events & RB_WAITFD_OUT)
|
27
|
+
wfds = &fdset;
|
28
|
+
if (events & RB_WAITFD_PRI)
|
29
|
+
efds = &fdset;
|
30
|
+
|
31
|
+
return rb_thread_select(fd + 1, rfds, wfds, efds, tvp);
|
32
|
+
}
|
33
|
+
|
34
|
+
#define rb_wait_for_single_fd(fd,events,tvp) \
|
35
|
+
my_wait_for_single_fd((fd),(events),(tvp))
|
36
|
+
#endif
|
@@ -15,8 +15,8 @@ module ActiveRecord
|
|
15
15
|
end
|
16
16
|
|
17
17
|
require 'fiber'
|
18
|
-
require 'eventmachine'
|
19
|
-
require 'mysql2'
|
18
|
+
require 'eventmachine'
|
19
|
+
require 'mysql2'
|
20
20
|
require 'active_record/connection_adapters/mysql2_adapter'
|
21
21
|
require 'active_record/fiber_patches'
|
22
22
|
|
@@ -35,25 +35,26 @@ module Mysql2
|
|
35
35
|
results = @client.async_result
|
36
36
|
@deferable.succeed(results)
|
37
37
|
rescue Exception => e
|
38
|
-
puts e.backtrace.join("\n\t")
|
39
38
|
@deferable.fail(e)
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
44
43
|
def query(sql, opts={})
|
45
|
-
if EM.reactor_running?
|
44
|
+
if ::EM.reactor_running?
|
46
45
|
super(sql, opts.merge(:async => true))
|
47
|
-
|
48
|
-
::EM.watch(self.socket, Watcher, self,
|
46
|
+
deferrable = ::EM::DefaultDeferrable.new
|
47
|
+
::EM.watch(self.socket, Watcher, self, deferrable).notify_readable = true
|
49
48
|
fiber = Fiber.current
|
50
|
-
|
49
|
+
deferrable.callback do |result|
|
51
50
|
fiber.resume(result)
|
52
51
|
end
|
53
|
-
|
52
|
+
deferrable.errback do |err|
|
54
53
|
fiber.resume(err)
|
55
54
|
end
|
56
|
-
Fiber.yield
|
55
|
+
Fiber.yield.tap do |result|
|
56
|
+
raise result if result.is_a?(Exception)
|
57
|
+
end
|
57
58
|
else
|
58
59
|
super(sql, opts)
|
59
60
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require 'mysql2'
|
3
|
+
require 'mysql2'
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
6
|
class Base
|
@@ -18,6 +18,9 @@ module ActiveRecord
|
|
18
18
|
end
|
19
19
|
|
20
20
|
module ConnectionAdapters
|
21
|
+
class Mysql2IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths) #:nodoc:
|
22
|
+
end
|
23
|
+
|
21
24
|
class Mysql2Column < Column
|
22
25
|
BOOL = "tinyint(1)"
|
23
26
|
def extract_default(default)
|
@@ -35,59 +38,10 @@ module ActiveRecord
|
|
35
38
|
end
|
36
39
|
|
37
40
|
def has_default?
|
38
|
-
return false if sql_type =~ /blob/i || type == :text #mysql forbids defaults on blob and text columns
|
41
|
+
return false if sql_type =~ /blob/i || type == :text # mysql forbids defaults on blob and text columns
|
39
42
|
super
|
40
43
|
end
|
41
44
|
|
42
|
-
# Returns the Ruby class that corresponds to the abstract data type.
|
43
|
-
def klass
|
44
|
-
case type
|
45
|
-
when :integer then Fixnum
|
46
|
-
when :float then Float
|
47
|
-
when :decimal then BigDecimal
|
48
|
-
when :datetime then Time
|
49
|
-
when :date then Date
|
50
|
-
when :timestamp then Time
|
51
|
-
when :time then Time
|
52
|
-
when :text, :string then String
|
53
|
-
when :binary then String
|
54
|
-
when :boolean then Object
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def type_cast(value)
|
59
|
-
return nil if value.nil?
|
60
|
-
case type
|
61
|
-
when :string then value
|
62
|
-
when :text then value
|
63
|
-
when :integer then value.to_i rescue value ? 1 : 0
|
64
|
-
when :float then value.to_f # returns self if it's already a Float
|
65
|
-
when :decimal then self.class.value_to_decimal(value)
|
66
|
-
when :datetime, :timestamp then value.class == Time ? value : self.class.string_to_time(value)
|
67
|
-
when :time then value.class == Time ? value : self.class.string_to_dummy_time(value)
|
68
|
-
when :date then value.class == Date ? value : self.class.string_to_date(value)
|
69
|
-
when :binary then value
|
70
|
-
when :boolean then self.class.value_to_boolean(value)
|
71
|
-
else value
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def type_cast_code(var_name)
|
76
|
-
case type
|
77
|
-
when :string then nil
|
78
|
-
when :text then nil
|
79
|
-
when :integer then "#{var_name}.to_i rescue #{var_name} ? 1 : 0"
|
80
|
-
when :float then "#{var_name}.to_f"
|
81
|
-
when :decimal then "#{self.class.name}.value_to_decimal(#{var_name})"
|
82
|
-
when :datetime, :timestamp then "#{var_name}.class == Time ? #{var_name} : #{self.class.name}.string_to_time(#{var_name})"
|
83
|
-
when :time then "#{var_name}.class == Time ? #{var_name} : #{self.class.name}.string_to_dummy_time(#{var_name})"
|
84
|
-
when :date then "#{var_name}.class == Date ? #{var_name} : #{self.class.name}.string_to_date(#{var_name})"
|
85
|
-
when :binary then nil
|
86
|
-
when :boolean then "#{self.class.name}.value_to_boolean(#{var_name})"
|
87
|
-
else nil
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
45
|
private
|
92
46
|
def simplified_type(field_type)
|
93
47
|
return :boolean if Mysql2Adapter.emulate_booleans && field_type.downcase.index(BOOL)
|
@@ -203,7 +157,7 @@ module ActiveRecord
|
|
203
157
|
end
|
204
158
|
|
205
159
|
def quote_column_name(name) #:nodoc:
|
206
|
-
@quoted_column_names[name] ||= "`#{name}`"
|
160
|
+
@quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`"
|
207
161
|
end
|
208
162
|
|
209
163
|
def quote_table_name(name) #:nodoc:
|
@@ -239,10 +193,7 @@ module ActiveRecord
|
|
239
193
|
|
240
194
|
def active?
|
241
195
|
return false unless @connection
|
242
|
-
@connection.
|
243
|
-
true
|
244
|
-
rescue Mysql2::Error
|
245
|
-
false
|
196
|
+
@connection.ping
|
246
197
|
end
|
247
198
|
|
248
199
|
def reconnect!
|
@@ -447,7 +398,7 @@ module ActiveRecord
|
|
447
398
|
if current_index != row[:Key_name]
|
448
399
|
next if row[:Key_name] == PRIMARY # skip the primary key
|
449
400
|
current_index = row[:Key_name]
|
450
|
-
indexes <<
|
401
|
+
indexes << Mysql2IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique] == 0, [], [])
|
451
402
|
end
|
452
403
|
|
453
404
|
indexes.last.columns << row[:Column_name]
|
@@ -623,7 +574,7 @@ module ActiveRecord
|
|
623
574
|
|
624
575
|
# increase timeout so mysql server doesn't disconnect us
|
625
576
|
wait_timeout = @config[:wait_timeout]
|
626
|
-
wait_timeout =
|
577
|
+
wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum)
|
627
578
|
variable_assignments << "@@wait_timeout = #{wait_timeout}"
|
628
579
|
|
629
580
|
execute("SET #{variable_assignments.join(', ')}", :skip_logging)
|