mysql2 0.2.19b6 → 0.2.19

Sign up to get free protection for your applications and to get access to all the features.
@@ -44,6 +44,17 @@ static VALUE rb_hash_dup(VALUE other) {
44
44
  mysql_client_wrapper *wrapper; \
45
45
  Data_Get_Struct(self, mysql_client_wrapper, wrapper)
46
46
 
47
+ /*
48
+ * compatability with mysql-connector-c, where LIBMYSQL_VERSION is the correct
49
+ * variable to use, but MYSQL_SERVER_VERSION gives the correct numbers when
50
+ * linking against the server itself
51
+ */
52
+ #ifdef LIBMYSQL_VERSION
53
+ #define MYSQL_LINK_VERSION LIBMYSQL_VERSION
54
+ #else
55
+ #define MYSQL_LINK_VERSION MYSQL_SERVER_VERSION
56
+ #endif
57
+
47
58
  /*
48
59
  * used to pass all arguments to mysql_real_connect while inside
49
60
  * rb_thread_blocking_region
@@ -182,13 +193,15 @@ static VALUE nogvl_close(void *ptr) {
182
193
  return Qnil;
183
194
  }
184
195
 
185
- static void rb_mysql_client_free(void * ptr) {
196
+ static void rb_mysql_client_free(void *ptr) {
186
197
  mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
187
198
 
188
- nogvl_close(wrapper);
189
-
190
- xfree(wrapper->client);
191
- xfree(ptr);
199
+ wrapper->refcount--;
200
+ if (wrapper->refcount == 0) {
201
+ nogvl_close(wrapper);
202
+ xfree(wrapper->client);
203
+ xfree(wrapper);
204
+ }
192
205
  }
193
206
 
194
207
  static VALUE allocate(VALUE klass) {
@@ -200,6 +213,7 @@ static VALUE allocate(VALUE klass) {
200
213
  wrapper->reconnect_enabled = 0;
201
214
  wrapper->connected = 0; /* means that a database connection is open */
202
215
  wrapper->initialized = 0; /* means that that the wrapper is initialized */
216
+ wrapper->refcount = 1;
203
217
  wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
204
218
  return obj;
205
219
  }
@@ -245,6 +259,25 @@ static VALUE rb_mysql_client_warning_count(VALUE self) {
245
259
  return UINT2NUM(warning_count);
246
260
  }
247
261
 
262
+ static VALUE rb_mysql_info(VALUE self) {
263
+ const char *info;
264
+ VALUE rb_str;
265
+ GET_CLIENT(self);
266
+
267
+ info = mysql_info(wrapper->client);
268
+
269
+ if (info == NULL) {
270
+ return Qnil;
271
+ }
272
+
273
+ rb_str = rb_str_new2(info);
274
+ #ifdef HAVE_RUBY_ENCODING_H
275
+ rb_enc_associate(rb_str, rb_utf8_encoding());
276
+ #endif
277
+
278
+ return rb_str;
279
+ }
280
+
248
281
  static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags) {
249
282
  struct nogvl_connect_args args;
250
283
  VALUE rv;
@@ -361,9 +394,7 @@ static VALUE nogvl_use_result(void *ptr) {
361
394
  static VALUE rb_mysql_client_async_result(VALUE self) {
362
395
  MYSQL_RES * result;
363
396
  VALUE resultObj;
364
- #ifdef HAVE_RUBY_ENCODING_H
365
- mysql2_result_wrapper * result_wrapper;
366
- #endif
397
+ VALUE current, is_streaming;
367
398
  GET_CLIENT(self);
368
399
 
369
400
  /* if we're not waiting on a result, do nothing */
@@ -377,7 +408,7 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
377
408
  return rb_raise_mysql2_error(wrapper);
378
409
  }
379
410
 
380
- VALUE is_streaming = rb_hash_aref(rb_iv_get(self, "@current_query_options"), sym_stream);
411
+ is_streaming = rb_hash_aref(rb_iv_get(self, "@current_query_options"), sym_stream);
381
412
  if(is_streaming == Qtrue) {
382
413
  result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_use_result, wrapper, RUBY_UBF_IO, 0);
383
414
  } else {
@@ -393,14 +424,11 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
393
424
  return Qnil;
394
425
  }
395
426
 
396
- resultObj = rb_mysql_result_to_obj(result);
397
- /* pass-through query options for result construction later */
398
- rb_iv_set(resultObj, "@query_options", rb_hash_dup(rb_iv_get(self, "@current_query_options")));
427
+ current = rb_hash_dup(rb_iv_get(self, "@current_query_options"));
428
+ RB_GC_GUARD(current);
429
+ Check_Type(current, T_HASH);
430
+ resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result);
399
431
 
400
- #ifdef HAVE_RUBY_ENCODING_H
401
- GetMysql2Result(resultObj, result_wrapper);
402
- result_wrapper->encoding = wrapper->encoding;
403
- #endif
404
432
  return resultObj;
405
433
  }
406
434
 
@@ -545,10 +573,13 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
545
573
  REQUIRE_CONNECTED(wrapper);
546
574
  args.mysql = wrapper->client;
547
575
 
548
- rb_iv_set(self, "@current_query_options", rb_hash_dup(rb_iv_get(self, "@query_options")));
549
- current = rb_iv_get(self, "@current_query_options");
576
+ current = rb_hash_dup(rb_iv_get(self, "@query_options"));
577
+ RB_GC_GUARD(current);
578
+ Check_Type(current, T_HASH);
579
+ rb_iv_set(self, "@current_query_options", current);
580
+
550
581
  if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
551
- opts = rb_funcall(current, intern_merge_bang, 1, opts);
582
+ rb_funcall(current, intern_merge_bang, 1, opts);
552
583
 
553
584
  if (rb_hash_aref(current, sym_async) == Qtrue) {
554
585
  async = 1;
@@ -926,10 +957,7 @@ static VALUE rb_mysql_client_store_result(VALUE self)
926
957
  {
927
958
  MYSQL_RES * result;
928
959
  VALUE resultObj;
929
- #ifdef HAVE_RUBY_ENCODING_H
930
- mysql2_result_wrapper * result_wrapper;
931
- #endif
932
-
960
+ VALUE current;
933
961
  GET_CLIENT(self);
934
962
 
935
963
  result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
@@ -942,16 +970,12 @@ static VALUE rb_mysql_client_store_result(VALUE self)
942
970
  return Qnil;
943
971
  }
944
972
 
945
- resultObj = rb_mysql_result_to_obj(result);
946
- /* pass-through query options for result construction later */
947
- rb_iv_set(resultObj, "@query_options", rb_hash_dup(rb_iv_get(self, "@current_query_options")));
973
+ current = rb_hash_dup(rb_iv_get(self, "@current_query_options"));
974
+ RB_GC_GUARD(current);
975
+ Check_Type(current, T_HASH);
976
+ resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result);
948
977
 
949
- #ifdef HAVE_RUBY_ENCODING_H
950
- GetMysql2Result(resultObj, result_wrapper);
951
- result_wrapper->encoding = wrapper->encoding;
952
- #endif
953
978
  return resultObj;
954
-
955
979
  }
956
980
 
957
981
  #ifdef HAVE_RUBY_ENCODING_H
@@ -1051,14 +1075,12 @@ static VALUE set_charset_name(VALUE self, VALUE value) {
1051
1075
  static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE capath, VALUE cipher) {
1052
1076
  GET_CLIENT(self);
1053
1077
 
1054
- if(!NIL_P(ca) || !NIL_P(key)) {
1055
- mysql_ssl_set(wrapper->client,
1056
- NIL_P(key) ? NULL : StringValuePtr(key),
1057
- NIL_P(cert) ? NULL : StringValuePtr(cert),
1058
- NIL_P(ca) ? NULL : StringValuePtr(ca),
1059
- NIL_P(capath) ? NULL : StringValuePtr(capath),
1060
- NIL_P(cipher) ? NULL : StringValuePtr(cipher));
1061
- }
1078
+ mysql_ssl_set(wrapper->client,
1079
+ NIL_P(key) ? NULL : StringValuePtr(key),
1080
+ NIL_P(cert) ? NULL : StringValuePtr(cert),
1081
+ NIL_P(ca) ? NULL : StringValuePtr(ca),
1082
+ NIL_P(capath) ? NULL : StringValuePtr(capath),
1083
+ NIL_P(cipher) ? NULL : StringValuePtr(cipher));
1062
1084
 
1063
1085
  return self;
1064
1086
  }
@@ -1081,14 +1103,15 @@ void init_mysql2_client() {
1081
1103
  int i;
1082
1104
  int dots = 0;
1083
1105
  const char *lib = mysql_get_client_info();
1084
- for (i = 0; lib[i] != 0 && MYSQL_SERVER_VERSION[i] != 0; i++) {
1106
+
1107
+ for (i = 0; lib[i] != 0 && MYSQL_LINK_VERSION[i] != 0; i++) {
1085
1108
  if (lib[i] == '.') {
1086
1109
  dots++;
1087
1110
  /* we only compare MAJOR and MINOR */
1088
1111
  if (dots == 2) break;
1089
1112
  }
1090
- if (lib[i] != MYSQL_SERVER_VERSION[i]) {
1091
- 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);
1113
+ if (lib[i] != MYSQL_LINK_VERSION[i]) {
1114
+ rb_raise(rb_eRuntimeError, "Incorrect MySQL client library version! This gem was compiled for %s but the client library is %s.", MYSQL_LINK_VERSION, lib);
1092
1115
  return;
1093
1116
  }
1094
1117
  }
@@ -1120,6 +1143,7 @@ void init_mysql2_client() {
1120
1143
  rb_define_method(cMysql2Client, "store_result", rb_mysql_client_store_result, 0);
1121
1144
  rb_define_method(cMysql2Client, "reconnect=", set_reconnect, 1);
1122
1145
  rb_define_method(cMysql2Client, "warning_count", rb_mysql_client_warning_count, 0);
1146
+ rb_define_method(cMysql2Client, "query_info_string", rb_mysql_info, 0);
1123
1147
  #ifdef HAVE_RUBY_ENCODING_H
1124
1148
  rb_define_method(cMysql2Client, "encoding", rb_mysql_client_encoding, 0);
1125
1149
  #endif
@@ -38,6 +38,8 @@ typedef struct {
38
38
  int active;
39
39
  int connected;
40
40
  int initialized;
41
+ int refcount;
42
+ int freed;
41
43
  MYSQL *client;
42
44
  } mysql_client_wrapper;
43
45
 
@@ -9,6 +9,7 @@ end
9
9
  have_func('rb_thread_blocking_region')
10
10
  have_func('rb_wait_for_single_fd')
11
11
  have_func('rb_hash_dup')
12
+ have_func('rb_intern3')
12
13
 
13
14
  # borrowed from mysqlplus
14
15
  # http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb
@@ -29,6 +30,14 @@ GLOB = "{#{dirs.join(',')}}/{mysql_config,mysql_config5}"
29
30
 
30
31
  if RUBY_PLATFORM =~ /mswin|mingw/
31
32
  inc, lib = dir_config('mysql')
33
+
34
+ # Ruby versions not incorporating the mkmf fix at
35
+ # https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/39717
36
+ # do not properly search for lib directories, and must be corrected
37
+ unless lib[-3, 3] == 'lib'
38
+ @libdir_basename = 'lib'
39
+ inc, lib = dir_config('mysql')
40
+ end
32
41
  exit 1 unless have_library("libmysql")
33
42
  elsif mc = (with_config('mysql-config') || Dir[GLOB].first) then
34
43
  mc = Dir[GLOB].first if mc == true
@@ -69,8 +78,13 @@ end
69
78
  if RbConfig::MAKEFILE_CONFIG['CC'] =~ /gcc/
70
79
  $CFLAGS << ' -Wall -funroll-loops'
71
80
 
72
- if hard_mysql_path = $libs[%r{-L(/[^ ]+)}, 1]
73
- $LDFLAGS << " -Wl,-rpath,#{hard_mysql_path}"
81
+ if libdir = $libs[%r{-L(/[^ ]+)}, 1]
82
+ # The following comment and test is borrowed from the Pg gem:
83
+ # Try to use runtime path linker option, even if RbConfig doesn't know about it.
84
+ # The rpath option is usually set implicit by dir_config(), but so far not on Mac OS X.
85
+ if RbConfig::CONFIG["RPATHFLAG"].to_s.empty? && try_link('int main() {return 0;}', " -Wl,-rpath,#{libdir}")
86
+ $LDFLAGS << " -Wl,-rpath,#{libdir}"
87
+ end
74
88
  end
75
89
  end
76
90
 
@@ -64,22 +64,33 @@ static void rb_mysql_result_mark(void * wrapper) {
64
64
  rb_gc_mark(w->fields);
65
65
  rb_gc_mark(w->rows);
66
66
  rb_gc_mark(w->encoding);
67
+ rb_gc_mark(w->client);
67
68
  }
68
69
  }
69
70
 
70
71
  /* this may be called manually or during GC */
71
72
  static void rb_mysql_result_free_result(mysql2_result_wrapper * wrapper) {
72
73
  if (wrapper && wrapper->resultFreed != 1) {
74
+ /* FIXME: this may call flush_use_result, which can hit the socket */
73
75
  mysql_free_result(wrapper->result);
74
76
  wrapper->resultFreed = 1;
75
77
  }
76
78
  }
77
79
 
78
80
  /* this is called during GC */
79
- static void rb_mysql_result_free(void * wrapper) {
80
- mysql2_result_wrapper * w = wrapper;
81
- /* FIXME: this may call flush_use_result, which can hit the socket */
82
- rb_mysql_result_free_result(w);
81
+ static void rb_mysql_result_free(void *ptr) {
82
+ mysql2_result_wrapper * wrapper = ptr;
83
+ rb_mysql_result_free_result(wrapper);
84
+
85
+ // If the GC gets to client first it will be nil
86
+ if (wrapper->client != Qnil) {
87
+ wrapper->client_wrapper->refcount--;
88
+ if (wrapper->client_wrapper->refcount == 0) {
89
+ xfree(wrapper->client_wrapper->client);
90
+ xfree(wrapper->client_wrapper);
91
+ }
92
+ }
93
+
83
94
  xfree(wrapper);
84
95
  }
85
96
 
@@ -114,15 +125,18 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int
114
125
 
115
126
  field = mysql_fetch_field_direct(wrapper->result, idx);
116
127
  if (symbolize_keys) {
117
- VALUE colStr;
118
128
  char buf[field->name_length+1];
119
129
  memcpy(buf, field->name, field->name_length);
120
130
  buf[field->name_length] = 0;
131
+
132
+ #ifdef HAVE_RB_INTERN3
133
+ rb_field = rb_intern3(buf, field->name_length, rb_utf8_encoding());
134
+ rb_field = ID2SYM(rb_field);
135
+ #else
136
+ VALUE colStr;
121
137
  colStr = rb_str_new2(buf);
122
- #ifdef HAVE_RUBY_ENCODING_H
123
- rb_enc_associate(colStr, rb_utf8_encoding());
124
- #endif
125
138
  rb_field = ID2SYM(rb_to_id(colStr));
139
+ #endif
126
140
  } else {
127
141
  rb_field = rb_str_new(field->name, field->name_length);
128
142
  #ifdef HAVE_RUBY_ENCODING_H
@@ -223,7 +237,11 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
223
237
  val = Qnil;
224
238
  break;
225
239
  case MYSQL_TYPE_BIT: /* BIT field (MySQL 5.0.3 and up) */
226
- val = rb_str_new(row[i], fieldLengths[i]);
240
+ if (castBool && fields[i].length == 1) {
241
+ val = *row[i] == 1 ? Qtrue : Qfalse;
242
+ }else{
243
+ val = rb_str_new(row[i], fieldLengths[i]);
244
+ }
227
245
  break;
228
246
  case MYSQL_TYPE_TINY: /* TINYINT field */
229
247
  if (castBool && fields[i].length == 1) {
@@ -376,6 +394,7 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
376
394
  GetMysql2Result(self, wrapper);
377
395
 
378
396
  defaults = rb_iv_get(self, "@query_options");
397
+ Check_Type(defaults, T_HASH);
379
398
  if (rb_hash_aref(defaults, sym_symbolize_keys) == Qtrue) {
380
399
  symbolizeKeys = 1;
381
400
  }
@@ -405,6 +424,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
405
424
  GetMysql2Result(self, wrapper);
406
425
 
407
426
  defaults = rb_iv_get(self, "@query_options");
427
+ Check_Type(defaults, T_HASH);
408
428
  if (rb_scan_args(argc, argv, "01&", &opts, &block) == 1) {
409
429
  opts = rb_funcall(defaults, intern_merge, 1, opts);
410
430
  } else {
@@ -558,7 +578,7 @@ static VALUE rb_mysql_result_count(VALUE self) {
558
578
  }
559
579
 
560
580
  /* Mysql2::Result */
561
- VALUE rb_mysql_result_to_obj(MYSQL_RES * r) {
581
+ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_RES *r) {
562
582
  VALUE obj;
563
583
  mysql2_result_wrapper * wrapper;
564
584
  obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper);
@@ -569,9 +589,16 @@ VALUE rb_mysql_result_to_obj(MYSQL_RES * r) {
569
589
  wrapper->result = r;
570
590
  wrapper->fields = Qnil;
571
591
  wrapper->rows = Qnil;
572
- wrapper->encoding = Qnil;
592
+ wrapper->encoding = encoding;
573
593
  wrapper->streamingComplete = 0;
594
+ wrapper->client = client;
595
+ wrapper->client_wrapper = DATA_PTR(client);
596
+ wrapper->client_wrapper->refcount++;
597
+
574
598
  rb_obj_call_init(obj, 0, NULL);
599
+
600
+ rb_iv_set(obj, "@query_options", options);
601
+
575
602
  return obj;
576
603
  }
577
604
 
@@ -2,11 +2,12 @@
2
2
  #define MYSQL2_RESULT_H
3
3
 
4
4
  void init_mysql2_result();
5
- VALUE rb_mysql_result_to_obj(MYSQL_RES * r);
5
+ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_RES *r);
6
6
 
7
7
  typedef struct {
8
8
  VALUE fields;
9
9
  VALUE rows;
10
+ VALUE client;
10
11
  VALUE encoding;
11
12
  unsigned int numberOfFields;
12
13
  unsigned long numberOfRows;
@@ -14,6 +15,7 @@ typedef struct {
14
15
  char streamingComplete;
15
16
  char resultFreed;
16
17
  MYSQL_RES *result;
18
+ mysql_client_wrapper *client_wrapper;
17
19
  } mysql2_result_wrapper;
18
20
 
19
21
  #define GetMysql2Result(obj, sval) (sval = (mysql2_result_wrapper*)DATA_PTR(obj));
@@ -5,13 +5,15 @@ require 'mysql2'
5
5
  module ActiveRecord
6
6
  class Base
7
7
  def self.mysql2_connection(config)
8
+ config = config.symbolize_keys
9
+
8
10
  config[:username] = 'root' if config[:username].nil?
9
11
 
10
12
  if Mysql2::Client.const_defined? :FOUND_ROWS
11
13
  config[:flags] = Mysql2::Client::FOUND_ROWS
12
14
  end
13
15
 
14
- client = Mysql2::Client.new(config.symbolize_keys)
16
+ client = Mysql2::Client.new(config)
15
17
  options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
16
18
  ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
17
19
  end
@@ -36,7 +36,8 @@ module Mysql2
36
36
  # force the encoding to utf8
37
37
  self.charset_name = opts[:encoding] || 'utf8'
38
38
 
39
- ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher))
39
+ ssl_options = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher)
40
+ ssl_set(*ssl_options) if ssl_options.any?
40
41
 
41
42
  if [:user,:pass,:hostname,:dbname,:db,:sock].any?{|k| @query_options.has_key?(k) }
42
43
  warn "============= WARNING FROM mysql2 ============="
@@ -60,6 +61,14 @@ module Mysql2
60
61
  @@default_query_options
61
62
  end
62
63
 
64
+ def query_info
65
+ info = query_info_string
66
+ return {} unless info
67
+ info_hash = {}
68
+ info.split.each_slice(2) { |s| info_hash[s[0].downcase.delete(':').to_sym] = s[1].to_i }
69
+ info_hash
70
+ end
71
+
63
72
  private
64
73
  def self.local_offset
65
74
  ::Time.local(2010).utc_offset.to_r / 86400
@@ -0,0 +1,5 @@
1
+ # Loaded by script/console. Land helpers here.
2
+
3
+ Pry.config.prompt = lambda do |context, nesting, pry|
4
+ "[mysql2] #{context}> "
5
+ end
@@ -1,3 +1,3 @@
1
1
  module Mysql2
2
- VERSION = "0.2.19b6"
2
+ VERSION = "0.2.19"
3
3
  end
@@ -81,11 +81,13 @@ describe Mysql2::Client do
81
81
  results = ssl_client.query("SHOW STATUS WHERE Variable_name = \"Ssl_version\" OR Variable_name = \"Ssl_cipher\"").to_a
82
82
  results[0]['Variable_name'].should eql('Ssl_cipher')
83
83
  results[0]['Value'].should_not be_nil
84
- results[0]['Value'].class.should eql(String)
84
+ results[0]['Value'].should be_kind_of(String)
85
+ results[0]['Value'].should_not be_empty
85
86
 
86
87
  results[1]['Variable_name'].should eql('Ssl_version')
87
88
  results[1]['Value'].should_not be_nil
88
- results[1]['Value'].class.should eql(String)
89
+ results[1]['Value'].should be_kind_of(String)
90
+ results[1]['Value'].should_not be_empty
89
91
  end
90
92
 
91
93
  it "should respond to #close" do
@@ -128,6 +130,42 @@ describe Mysql2::Client do
128
130
  end
129
131
  end
130
132
 
133
+ it "should respond to #query_info" do
134
+ @client.should respond_to(:query_info)
135
+ end
136
+
137
+ context "#query_info" do
138
+ context "when no info present" do
139
+ before(:each) do
140
+ @client.query('select 1')
141
+ end
142
+ it "should 0" do
143
+ @client.query_info.should be_empty
144
+ @client.query_info_string.should be_nil
145
+ end
146
+ end
147
+ context "when has some info" do
148
+ before(:each) do
149
+ @client.query "USE test"
150
+ @client.query "CREATE TABLE IF NOT EXISTS infoTest (`id` int(11) NOT NULL AUTO_INCREMENT, blah INT(11), PRIMARY KEY (`id`))"
151
+ end
152
+
153
+ after(:each) do
154
+ @client.query "DROP TABLE infoTest"
155
+ end
156
+
157
+ before(:each) do
158
+ # http://dev.mysql.com/doc/refman/5.0/en/mysql-info.html says
159
+ # # Note that mysql_info() returns a non-NULL value for INSERT ... VALUES only for the multiple-row form of the statement (that is, only if multiple value lists are specified).
160
+ @client.query("INSERT INTO infoTest (blah) VALUES (1234),(4535)")
161
+ end
162
+ it "should retrieve it" do
163
+ @client.query_info.should == {:records => 2, :duplicates => 0, :warnings => 0}
164
+ @client.query_info_string.should eq 'Records: 2 Duplicates: 0 Warnings: 0'
165
+ end
166
+ end
167
+ end
168
+
131
169
  it "should expect connect_timeout to be a positive integer" do
132
170
  lambda {
133
171
  Mysql2::Client.new(:connect_timeout => -1)
@@ -255,10 +293,10 @@ describe Mysql2::Client do
255
293
  mark[:END] = Time.now
256
294
  mark.include?(:USR1).should be_true
257
295
  (mark[:USR1] - mark[:START]).should >= 1
258
- (mark[:USR1] - mark[:START]).should < 1.1
296
+ (mark[:USR1] - mark[:START]).should < 1.3
259
297
  (mark[:END] - mark[:USR1]).should > 0.9
260
298
  (mark[:END] - mark[:START]).should >= 2
261
- (mark[:END] - mark[:START]).should < 2.1
299
+ (mark[:END] - mark[:START]).should < 2.3
262
300
  Process.kill(:TERM, pid)
263
301
  Process.waitpid2(pid)
264
302
  ensure
@@ -160,11 +160,16 @@ describe Mysql2::Result do
160
160
  @test_result['null_test'].should eql(nil)
161
161
  end
162
162
 
163
- it "should return Fixnum for a BIT value" do
163
+ it "should return String for a BIT(64) value" do
164
164
  @test_result['bit_test'].class.should eql(String)
165
165
  @test_result['bit_test'].should eql("\000\000\000\000\000\000\000\005")
166
166
  end
167
167
 
168
+ it "should return String for a BIT(1) value" do
169
+ @test_result['single_bit_test'].class.should eql(String)
170
+ @test_result['single_bit_test'].should eql("\001")
171
+ end
172
+
168
173
  it "should return Fixnum for a TINYINT value" do
169
174
  [Fixnum, Bignum].should include(@test_result['tiny_int_test'].class)
170
175
  @test_result['tiny_int_test'].should eql(1)
@@ -188,6 +193,20 @@ describe Mysql2::Result do
188
193
  @client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2},#{id3})"
189
194
  end
190
195
 
196
+ it "should return TrueClass or FalseClass for a BIT(1) value if :cast_booleans is enabled" do
197
+ @client.query 'INSERT INTO mysql2_test (single_bit_test) VALUES (1)'
198
+ id1 = @client.last_id
199
+ @client.query 'INSERT INTO mysql2_test (single_bit_test) VALUES (0)'
200
+ id2 = @client.last_id
201
+
202
+ result1 = @client.query "SELECT single_bit_test FROM mysql2_test WHERE id = #{id1}", :cast_booleans => true
203
+ result2 = @client.query "SELECT single_bit_test FROM mysql2_test WHERE id = #{id2}", :cast_booleans => true
204
+ result1.first['single_bit_test'].should be_true
205
+ result2.first['single_bit_test'].should be_false
206
+
207
+ @client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2})"
208
+ end
209
+
191
210
  it "should return Fixnum for a SMALLINT value" do
192
211
  [Fixnum, Bignum].should include(@test_result['small_int_test'].class)
193
212
  @test_result['small_int_test'].should eql(10)
@@ -14,6 +14,7 @@ RSpec.configure do |config|
14
14
  id MEDIUMINT NOT NULL AUTO_INCREMENT,
15
15
  null_test VARCHAR(10),
16
16
  bit_test BIT(64),
17
+ single_bit_test BIT(1),
17
18
  tiny_int_test TINYINT,
18
19
  bool_cast_test TINYINT(1),
19
20
  small_int_test SMALLINT,
@@ -50,7 +51,7 @@ RSpec.configure do |config|
50
51
  client.query "DELETE FROM mysql2_test;"
51
52
  client.query %[
52
53
  INSERT INTO mysql2_test (
53
- null_test, bit_test, tiny_int_test, bool_cast_test, small_int_test, medium_int_test, int_test, big_int_test,
54
+ null_test, bit_test, single_bit_test, tiny_int_test, bool_cast_test, small_int_test, medium_int_test, int_test, big_int_test,
54
55
  float_test, float_zero_test, double_test, decimal_test, decimal_zero_test, date_test, date_time_test, timestamp_test, time_test,
55
56
  year_test, char_test, varchar_test, binary_test, varbinary_test, tiny_blob_test,
56
57
  tiny_text_test, blob_test, text_test, medium_blob_test, medium_text_test,
@@ -58,7 +59,7 @@ RSpec.configure do |config|
58
59
  )
59
60
 
60
61
  VALUES (
61
- NULL, b'101', 1, 1, 10, 10, 10, 10,
62
+ NULL, b'101', b'1', 1, 1, 10, 10, 10, 10,
62
63
  10.3, 0, 10.3, 10.3, 0, '2010-4-4', '2010-4-4 11:44:00', '2010-4-4 11:44:00', '11:44:00',
63
64
  2009, "test", "test", "test", "test", "test",
64
65
  "test", "test", "test", "test", "test",
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mysql2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.19b6
5
- prerelease: 6
4
+ version: 0.2.19
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Brian Lopez
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-21 00:00:00.000000000 Z
12
+ date: 2013-07-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -82,7 +82,6 @@ extensions:
82
82
  - ext/mysql2/extconf.rb
83
83
  extra_rdoc_files: []
84
84
  files:
85
- - CHANGELOG.md
86
85
  - MIT-LICENSE
87
86
  - README.md
88
87
  - ext/mysql2/client.c
@@ -95,14 +94,12 @@ files:
95
94
  - ext/mysql2/result.c
96
95
  - ext/mysql2/result.h
97
96
  - ext/mysql2/wait_for_single_fd.h
98
- - lib/active_record/connection_adapters/em_mysql2_adapter.rb
99
97
  - lib/active_record/connection_adapters/mysql2_adapter.rb
100
- - lib/active_record/fiber_patches.rb
101
98
  - lib/arel/engines/sql/compilers/mysql2_compiler.rb
102
99
  - lib/mysql2.rb
103
100
  - lib/mysql2/client.rb
101
+ - lib/mysql2/console.rb
104
102
  - lib/mysql2/em.rb
105
- - lib/mysql2/em_fiber.rb
106
103
  - lib/mysql2/error.rb
107
104
  - lib/mysql2/result.rb
108
105
  - lib/mysql2/version.rb
@@ -111,7 +108,6 @@ files:
111
108
  - examples/eventmachine.rb
112
109
  - examples/threaded.rb
113
110
  - spec/configuration.yml.example
114
- - spec/em/em_fiber_spec.rb
115
111
  - spec/em/em_spec.rb
116
112
  - spec/mysql2/client_spec.rb
117
113
  - spec/mysql2/error_spec.rb
@@ -119,7 +115,8 @@ files:
119
115
  - spec/rcov.opts
120
116
  - spec/spec_helper.rb
121
117
  homepage: http://github.com/brianmario/mysql2
122
- licenses: []
118
+ licenses:
119
+ - MIT
123
120
  post_install_message:
124
121
  rdoc_options:
125
122
  - --charset=UTF-8
@@ -134,9 +131,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
134
131
  required_rubygems_version: !ruby/object:Gem::Requirement
135
132
  none: false
136
133
  requirements:
137
- - - ! '>'
134
+ - - ! '>='
138
135
  - !ruby/object:Gem::Version
139
- version: 1.3.1
136
+ version: '0'
140
137
  requirements: []
141
138
  rubyforge_project:
142
139
  rubygems_version: 1.8.23
@@ -147,7 +144,6 @@ test_files:
147
144
  - examples/eventmachine.rb
148
145
  - examples/threaded.rb
149
146
  - spec/configuration.yml.example
150
- - spec/em/em_fiber_spec.rb
151
147
  - spec/em/em_spec.rb
152
148
  - spec/mysql2/client_spec.rb
153
149
  - spec/mysql2/error_spec.rb
@@ -1,221 +0,0 @@
1
- # Changelog
2
-
3
- ## 0.2.19 (not yet released)
4
- ## 0.2.19b5 (not yet released)
5
- * builds on Ruby 2.0-head and Rubinius 2.0-dev
6
- * encoding names now stored in a Gperf lookup rather than an array
7
- * long-standing bug fix: options set on a single query must not be applied to subsequent queries
8
- * add method warning_count
9
- * add method abandon_results!
10
- * add setter for reconnect option
11
- * remove options method (added in 0.3.12b1)
12
- * support microsecond Time resolution
13
- * several INT / UINT fixes
14
-
15
- ## 0.2.19b4 (August 22, 2012)
16
- * add write_timeout as well
17
-
18
- ## 0.2.19b3 (August 22, 2012)
19
- * several INT / LONG fixes
20
- * fix linking to MySQL 5.5
21
-
22
- ## 0.2.19b2 (August 10, 2012)
23
- * more_results is now more_results?
24
-
25
- ## 0.2.19b1 (August 8, 2012)
26
- * several threading and async bug fixes
27
- * better handling of read and write timeouts
28
- * add :local_infile connection option
29
- * add MULTI_STATEMENTS connection flag and methods store_result, next_result, more_results
30
- * add select_db and options methods
31
- * add :stream query option
32
- * add support for utf8mb4 encoding
33
- * deprecation warnings for the :user, :pass, :hostname, :dbname, :db, :sock connection options
34
-
35
- ## 0.2.18 (December 6th, 2011)
36
- * change mysql error detection strategy from using mysql_field_count to the more explicit mysql_errno
37
- * bugfix to avoid race condition with active connections that error out
38
- * revert back to using xmalloc/xfree for allocations
39
- * avoid potentially unsafe Ruby C API usage w/o GVL
40
- * reacquire GVL before retrying on EINTR on connect
41
-
42
- ## 0.2.17 (November 9th, 2011)
43
-
44
- ## 0.2.16 (November 9th, 2011)
45
-
46
- ## 0.2.15 (November 9th, 2011)
47
-
48
- ## 0.2.14 (November 9th, 2011)
49
- * use rb_wait_for_single_fd() if available
50
- * fixed a bug with inheriting query options
51
- * remove ext/ from the default loadpath
52
- * fix build issues on OSX with Xcode 4.2 (gcc-llvm compiler)
53
-
54
- ## 0.2.13 (August 16th, 2011)
55
- * fix stupid bug around symbol encoding support (thanks coderrr!)
56
-
57
- ## 0.2.12 (August 16th, 2011)
58
- * ensure symbolized column names support encodings in 1.9
59
- * plugging sql vulnerability in mysql2 adapter
60
-
61
- ## 0.2.11 (June 17th, 2011)
62
- * fix bug in Time/DateTime range detection
63
- * (win32) fix bug where the Mysql2::Client object wasn't cleaned up properly if interrupted during a query
64
- * add Mysql2::Result#count (aliased as size) to get the row count for the dataset
65
- this can be especially helpful if you want to get the number of rows without having to inflate
66
- the entire dataset into ruby (since this happens lazily)
67
-
68
- ## 0.2.10 (June 15th, 2011)
69
- * bug fix for Time/DateTime usage depending on 32/64bit Ruby
70
-
71
- ## 0.2.9 (June 15th, 2011)
72
- * fix a long standing bug where a signal would interrupt rb_thread_select and put the connection in a permanently broken state
73
- * turn on casting in the ActiveRecord again, users can disable it if they need to for performance reasons
74
-
75
- ## 0.2.8 (June 14th, 2011)
76
- * disable async support, and access to the underlying file descriptor under Windows. It's never worked reliably and ruby-core has a lot of work to do in order to make it possible.
77
- * added support for turning eager-casting off. This is especially useful in ORMs that will lazily cast values upon access.
78
- * added a warning if a 0.2.x release is being used with ActiveRecord 3.1 since both the 0.2.x releases and AR 3.1 have mysql2 adapters, we want you to use the one in AR 3.1
79
- * added Mysql2::Client.escape (class-level method)
80
- * disabled eager-casting in the bundled ActiveRecord adapter (for Rails 3.0 or less)
81
-
82
- ## 0.2.7 (March 28th, 2011)
83
- * various fixes for em_mysql2 and fiber usage
84
- * use our own Mysql2IndexDefinition class for better compatibility across ActiveRecord versions
85
- * ensure the query is a string earlier in the Mysql2::Client#query codepath for 1.9
86
- * only set binary ruby encoding on fields that have a binary flag *and* encoding set
87
- * a few various optimizations
88
- * add support for :read_timeout to be set on a connection
89
- * Fix to install with MariDB on Windows
90
- * add fibered em connection without activerecord
91
- * fix some 1.9.3 compilation warnings
92
- * add LD_RUN_PATH when using hard coded mysql paths - this should help users with MySQL installed in non-standard locations
93
- * for windows support, duplicate the socket from libmysql and create a temporary CRT fd
94
- * fix for handling years before 1970 on Windows
95
- * fixes to the Fiber adapter
96
- * set wait_timeout maximum on Windows to 2147483
97
- * update supported range for Time objects
98
- * upon being required, make sure the libmysql we're using is the one we were built against
99
- * add Mysql2::Client#thread_id
100
- * add Mysql2::Client#ping
101
- * switch connection check in AR adapter to use Mysql2::Client#ping for efficiency
102
- * prefer linking against thread-safe version of libmysqlclient
103
- * define RSTRING_NOT_MODIFIED for an awesome rbx speed boost
104
- * expose Mysql2::Client#encoding in 1.9, make sure we set the error message and sqlstate encodings accordingly
105
- * do not segfault when raising for invalid charset (found in 1.9.3dev)
106
-
107
- ## 0.2.6 (October 19th, 2010)
108
- * version bump since the 0.2.5 win32 binary gems were broken
109
-
110
- ## 0.2.5 (October 19th, 2010)
111
- * fixes for easier Win32 binary gem deployment for targeting 1.8 and 1.9 in the same gem
112
- * refactor of connection checks and management to avoid race conditions with the GC/threading to prevent the unexpected loss of connections
113
- * update the default flags during connection
114
- * add support for setting wait_timeout on AR adapter
115
- * upgrade to rspec2
116
- * bugfix for an edge case where the GC would clean up a Mysql2::Client object before the underlying MYSQL pointer had been initialized
117
- * fix to CFLAGS to allow compilation on SPARC with sunstudio compiler - Anko painting <anko.com+github@gmail.com>
118
-
119
- ## 0.2.4 (September 17th, 2010)
120
- * a few patches for win32 support from Luis Lavena - thanks man!
121
- * bugfix from Eric Wong to avoid a potential stack overflow during Mysql2::Client#escape
122
- * added the ability to turn internal row caching on/off via the :cache_rows => true/false option
123
- * a couple of small patches for rbx compatibility
124
- * set IndexDefinition#length in AR adapter - Kouhei Yanagita <yanagi@shakenbu.org>
125
- * fix a long-standing data corruption bug - thank you thank you thank you to @joedamato (http://github.com/ice799)
126
- * bugfix from calling mysql_close on a closed/freed connection surfaced by the above fix
127
-
128
- ## 0.2.3 (August 20th, 2010)
129
- * connection flags can now be passed to the constructor via the :flags key
130
- * switch AR adapter connection over to use FOUND_ROWS option
131
- * patch to ensure we use DateTime objects in place of Time for timestamps that are out of the supported range on 32bit platforms < 1.9.2
132
-
133
- ## 0.2.2 (August 19th, 2010)
134
- * Change how AR adapter would send initial commands upon connecting
135
- ** we can make multiple session variable assignments in a single query
136
- * fix signal handling when waiting on queries
137
- * retry connect if interrupted by signals
138
-
139
- ## 0.2.1 (August 16th, 2010)
140
- * bring mysql2 ActiveRecord adapter back into gem
141
-
142
- ## 0.2.0 (August 16th, 2010)
143
- * switch back to letting libmysql manage all allocation/thread-state/freeing for the connection
144
- * cache various numeric type conversions in hot-spots of the code for a little speed boost
145
- * ActiveRecord adapter moved into Rails 3 core
146
- ** Don't worry 2.3.x users! We'll either release the adapter as a separate gem, or try to get it into 2.3.9
147
- * Fix for the "closed MySQL connection" error (GH #31)
148
- * Fix for the "can't modify frozen object" error in 1.9.2 (GH #37)
149
- * Introduce cascading query and result options (more info in README)
150
- * Sequel adapter pulled into core (will be in the next release - 3.15.0 at the time of writing)
151
- * add a safety check when attempting to send a query before a result has been fetched
152
-
153
- ## 0.1.9 (July 17th, 2010)
154
- * Support async ActiveRecord access with fibers and EventMachine (mperham)
155
- * string encoding support for 1.9, respecting Encoding.default_internal
156
- * added support for rake-compiler (tenderlove)
157
- * bugfixes for ActiveRecord driver
158
- ** one minor bugfix for TimeZone support
159
- ** fix the select_rows method to return what it should according to the docs (r-stu31)
160
- * Mysql2::Client#fields method added - returns the array of field names from a resultset, as strings
161
- * Sequel adapter
162
- ** bugfix regarding sybolized field names (Eric Wong)
163
- ** fix query logging in Sequel adapter
164
- * Lots of nice code cleanup (tenderlove)
165
- ** Mysql2::Error definition moved to pure-Ruby
166
- ** Mysql2::client#initialize definition moved to pure-Ruby
167
- ** Mysql2::Result partially moved to pure-Ruby
168
-
169
- ## 0.1.8 (June 2nd, 2010)
170
- * fixes for AR adapter for timezone juggling
171
- * fixes to be able to run benchmarks and specs under 1.9.2
172
-
173
- ## 0.1.7 (May 22nd, 2010)
174
- * fix a bug when using the disconnect! method on a closed connection in the AR driver
175
-
176
- ## 0.1.6 (May 14th, 2010)
177
- * more fixes to the AR adapter related to casting
178
- * add missing index creation override method to AR adapter
179
- * added sql_state and error_number methods to the Mysql2::Error exception class
180
-
181
- ## 0.1.5 (May 12th, 2010)
182
- * quite a few patches from Eric Wong related to thread-safety, non-blocking I/O and general cleanup
183
- ** wrap mysql_real_connect with rb_thread_blocking_region
184
- ** release GVL for possibly blocking mysql_* library calls
185
- ** [cleanup] quiet down warnings
186
- ** [cleanup] make all C symbols static
187
- ** add Mysql2::Client#close method
188
- ** correctly free the wrapped result in case of EOF
189
- ** Fix memory leak from the result wrapper struct itself
190
- ** make Mysql2::Client destructor safely non-blocking
191
- * bug fixes for ActiveRecord adapter
192
- ** added casting for default values since they all come back from Mysql as strings (!?!)
193
- ** missing constant was added
194
- ** fixed a typo in the show_variable method
195
- * switched over sscanf for date/time parsing in C
196
- * made some specs a little finer-grained
197
- * initial Sequel adapter added
198
- * updated query benchmarks to reflect the difference between casting in C and in Ruby
199
-
200
- ## 0.1.4 (April 23rd, 2010)
201
- * optimization: implemented a local cache for rows that are lazily created in ruby during iteration. The MySQL C result is freed as soon as all the results have been cached
202
- * optimization: implemented a local cache for field names so every row reuses the same objects as field names/keys
203
- * refactor the Mysql2 connection adapter for ActiveRecord to not extend the Mysql adapter - now being a free-standing connection adapter
204
-
205
- ## 0.1.3 (April 15th, 2010)
206
- * added an EventMachine Deferrable API
207
- * added an ActiveRecord connection adapter
208
- ** should be compatible with 2.3.5 and 3.0 (including Arel)
209
-
210
- ## 0.1.2 (April 9th, 2010)
211
- * fix a bug (copy/paste fail) around checking for empty TIME values and returning nil (thanks @marius)
212
-
213
- ## 0.1.1 (April 6th, 2010)
214
- * added affected_rows method (mysql_affected_rows)
215
- * added last_id method (last_insert_id)
216
- * enable reconnect option by default
217
- * added initial async query support
218
- * updated extconf (thanks to the mysqlplus project) for easier gem building
219
-
220
- ## 0.1.0 (April 6th, 2010)
221
- * initial release
@@ -1,64 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # AR adapter for using a fibered mysql2 connection with EM
4
- # This adapter should be used within Thin or Unicorn with the rack-fiber_pool middleware.
5
- # Just update your database.yml's adapter to be 'em_mysql2'
6
-
7
- module ActiveRecord
8
- class Base
9
- def self.em_mysql2_connection(config)
10
- client = ::Mysql2::Fibered::Client.new(config.symbolize_keys)
11
- options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
12
- ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
13
- end
14
- end
15
- end
16
-
17
- require 'fiber'
18
- require 'eventmachine'
19
- require 'mysql2'
20
- require 'active_record/connection_adapters/mysql2_adapter'
21
- require 'active_record/fiber_patches'
22
-
23
- module Mysql2
24
- module Fibered
25
- class Client < ::Mysql2::Client
26
- module Watcher
27
- def initialize(client, deferable)
28
- @client = client
29
- @deferable = deferable
30
- end
31
-
32
- def notify_readable
33
- begin
34
- detach
35
- results = @client.async_result
36
- @deferable.succeed(results)
37
- rescue Exception => e
38
- @deferable.fail(e)
39
- end
40
- end
41
- end
42
-
43
- def query(sql, opts={})
44
- if ::EM.reactor_running?
45
- super(sql, opts.merge(:async => true))
46
- deferrable = ::EM::DefaultDeferrable.new
47
- ::EM.watch(self.socket, Watcher, self, deferrable).notify_readable = true
48
- fiber = Fiber.current
49
- deferrable.callback do |result|
50
- fiber.resume(result)
51
- end
52
- deferrable.errback do |err|
53
- fiber.resume(err)
54
- end
55
- Fiber.yield.tap do |result|
56
- raise result if result.is_a?(Exception)
57
- end
58
- else
59
- super(sql, opts)
60
- end
61
- end
62
- end
63
- end
64
- end
@@ -1,132 +0,0 @@
1
- # Necessary monkeypatching to make AR fiber-friendly.
2
-
3
- module ActiveRecord
4
- module ConnectionAdapters
5
-
6
- def self.fiber_pools
7
- @fiber_pools ||= []
8
- end
9
- def self.register_fiber_pool(fp)
10
- fiber_pools << fp
11
- end
12
-
13
- class FiberedMonitor
14
- class Queue
15
- def initialize
16
- @queue = []
17
- end
18
-
19
- def wait(timeout)
20
- t = timeout || 5
21
- fiber = Fiber.current
22
- x = EM::Timer.new(t) do
23
- @queue.delete(fiber)
24
- fiber.resume(false)
25
- end
26
- @queue << fiber
27
- Fiber.yield.tap do
28
- x.cancel
29
- end
30
- end
31
-
32
- def signal
33
- fiber = @queue.pop
34
- fiber.resume(true) if fiber
35
- end
36
- end
37
-
38
- def synchronize
39
- yield
40
- end
41
-
42
- def new_cond
43
- Queue.new
44
- end
45
- end
46
-
47
- # ActiveRecord's connection pool is based on threads. Since we are working
48
- # with EM and a single thread, multiple fiber design, we need to provide
49
- # our own connection pool that keys off of Fiber.current so that different
50
- # fibers running in the same thread don't try to use the same connection.
51
- class ConnectionPool
52
- def initialize(spec)
53
- @spec = spec
54
-
55
- # The cache of reserved connections mapped to threads
56
- @reserved_connections = {}
57
-
58
- # The mutex used to synchronize pool access
59
- @connection_mutex = FiberedMonitor.new
60
- @queue = @connection_mutex.new_cond
61
-
62
- # default 5 second timeout unless on ruby 1.9
63
- @timeout = spec.config[:wait_timeout] || 5
64
-
65
- # default max pool size to 5
66
- @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
67
-
68
- @connections = []
69
- @checked_out = []
70
- @automatic_reconnect = true
71
- @tables = {}
72
-
73
- @columns = Hash.new do |h, table_name|
74
- h[table_name] = with_connection do |conn|
75
-
76
- # Fetch a list of columns
77
- conn.columns(table_name, "#{table_name} Columns").tap do |columns|
78
-
79
- # set primary key information
80
- columns.each do |column|
81
- column.primary = column.name == primary_keys[table_name]
82
- end
83
- end
84
- end
85
- end
86
-
87
- @columns_hash = Hash.new do |h, table_name|
88
- h[table_name] = Hash[columns[table_name].map { |col|
89
- [col.name, col]
90
- }]
91
- end
92
-
93
- @primary_keys = Hash.new do |h, table_name|
94
- h[table_name] = with_connection do |conn|
95
- table_exists?(table_name) ? conn.primary_key(table_name) : 'id'
96
- end
97
- end
98
- end
99
-
100
- def clear_stale_cached_connections!
101
- cache = @reserved_connections
102
- keys = Set.new(cache.keys)
103
-
104
- ActiveRecord::ConnectionAdapters.fiber_pools.each do |pool|
105
- pool.busy_fibers.each_pair do |object_id, fiber|
106
- keys.delete(object_id)
107
- end
108
- end
109
-
110
- keys.each do |key|
111
- next unless cache.has_key?(key)
112
- checkin cache[key]
113
- cache.delete(key)
114
- end
115
- end
116
-
117
- private
118
-
119
- def current_connection_id #:nodoc:
120
- Fiber.current.object_id
121
- end
122
-
123
- def checkout_and_verify(c)
124
- @checked_out << c
125
- c.run_callbacks :checkout
126
- c.verify!
127
- c
128
- end
129
- end
130
-
131
- end
132
- end
@@ -1,31 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'mysql2/em'
4
- require 'fiber'
5
-
6
- module Mysql2
7
- module EM
8
- module Fiber
9
- class Client < ::Mysql2::EM::Client
10
- def query(sql, opts={})
11
- if ::EM.reactor_running?
12
- deferable = super(sql, opts)
13
-
14
- fiber = ::Fiber.current
15
- deferable.callback do |result|
16
- fiber.resume(result)
17
- end
18
- deferable.errback do |err|
19
- fiber.resume(err)
20
- end
21
- ::Fiber.yield.tap do |result|
22
- raise result if result.is_a?(::Exception)
23
- end
24
- else
25
- super(sql, opts)
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,22 +0,0 @@
1
- # encoding: UTF-8
2
- if defined? EventMachine && defined? Fiber
3
- require 'spec_helper'
4
- require 'mysql2/em_fiber'
5
-
6
- describe Mysql2::EM::Fiber::Client do
7
- it 'should support queries' do
8
- results = []
9
- EM.run do
10
- Fiber.new {
11
- client1 = Mysql2::EM::Fiber::Client.new DatabaseCredentials['root']
12
- results = client1.query "SELECT sleep(0.1) as first_query"
13
- EM.stop_event_loop
14
- }.resume
15
- end
16
-
17
- results.first.keys.should include("first_query")
18
- end
19
- end
20
- else
21
- puts "Either EventMachine or Fibers not available. Skipping tests that use them."
22
- end