mysql2 0.2.19b6 → 0.2.19

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.
@@ -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