mysql2 0.3.11 → 0.3.12b1

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.
@@ -33,10 +33,12 @@ void init_mysql2_client();
33
33
 
34
34
  typedef struct {
35
35
  VALUE encoding;
36
- int active;
36
+ VALUE active_thread; /* rb_thread_current() or Qnil */
37
37
  int reconnect_enabled;
38
- int closed;
38
+ int active;
39
+ int connected;
40
+ int initialized;
39
41
  MYSQL *client;
40
42
  } mysql_client_wrapper;
41
43
 
42
- #endif
44
+ #endif
@@ -17,6 +17,7 @@ dirs = ENV['PATH'].split(File::PATH_SEPARATOR) + %w[
17
17
  /opt/local/mysql
18
18
  /opt/local/lib/mysql5
19
19
  /usr
20
+ /usr/mysql
20
21
  /usr/local
21
22
  /usr/local/mysql
22
23
  /usr/local/mysql-*
@@ -61,13 +62,13 @@ end
61
62
  asplode h unless have_header h
62
63
  end
63
64
 
64
- unless RUBY_PLATFORM =~ /mswin/ or RUBY_PLATFORM =~ /sparc/
65
+ # GCC specific flags
66
+ if RbConfig::MAKEFILE_CONFIG['CC'] =~ /gcc/
65
67
  $CFLAGS << ' -Wall -funroll-loops'
66
- end
67
- # $CFLAGS << ' -O0 -ggdb3 -Wextra'
68
68
 
69
- if hard_mysql_path = $libs[%r{-L(/[^ ]+)}, 1]
70
- $LDFLAGS << " -Wl,-rpath,#{hard_mysql_path}"
69
+ if hard_mysql_path = $libs[%r{-L(/[^ ]+)}, 1]
70
+ $LDFLAGS << " -Wl,-rpath,#{hard_mysql_path}"
71
+ end
71
72
  end
72
73
 
73
74
  create_makefile('mysql2/mysql2')
@@ -55,7 +55,7 @@ static VALUE intern_encoding_from_charset;
55
55
  static ID intern_new, intern_utc, intern_local, intern_encoding_from_charset_code,
56
56
  intern_localtime, intern_local_offset, intern_civil, intern_new_offset;
57
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;
58
+ sym_local, sym_utc, sym_cast_booleans, sym_cache_rows, sym_cast, sym_stream;
59
59
  static ID intern_merge;
60
60
 
61
61
  static void rb_mysql_result_mark(void * wrapper) {
@@ -163,11 +163,10 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
163
163
  #endif
164
164
 
165
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) {
166
+ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezone, int symbolizeKeys, int asArray, int castBool, int cast, MYSQL_FIELD * fields) {
167
167
  VALUE rowVal;
168
168
  mysql2_result_wrapper * wrapper;
169
169
  MYSQL_ROW row;
170
- MYSQL_FIELD * fields = NULL;
171
170
  unsigned int i = 0;
172
171
  unsigned long * fieldLengths;
173
172
  void * ptr;
@@ -193,7 +192,6 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
193
192
  } else {
194
193
  rowVal = rb_hash_new();
195
194
  }
196
- fields = mysql_fetch_fields(wrapper->result);
197
195
  fieldLengths = mysql_fetch_lengths(wrapper->result);
198
196
  if (wrapper->fields == Qnil) {
199
197
  wrapper->numberOfFields = mysql_num_fields(wrapper->result);
@@ -225,7 +223,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
225
223
  break;
226
224
  case MYSQL_TYPE_TINY: // TINYINT field
227
225
  if (castBool && fields[i].length == 1) {
228
- val = *row[i] == '1' ? Qtrue : Qfalse;
226
+ val = *row[i] != '0' ? Qtrue : Qfalse;
229
227
  break;
230
228
  }
231
229
  case MYSQL_TYPE_SHORT: // SMALLINT field
@@ -237,7 +235,9 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
237
235
  break;
238
236
  case MYSQL_TYPE_DECIMAL: // DECIMAL or NUMERIC field
239
237
  case MYSQL_TYPE_NEWDECIMAL: // Precision math DECIMAL or NUMERIC field (MySQL 5.0.3 and up)
240
- if (strtod(row[i], NULL) == 0.000000){
238
+ if (fields[i].decimals == 0) {
239
+ val = rb_cstr2inum(row[i], 10);
240
+ } else if (strtod(row[i], NULL) == 0.000000){
241
241
  val = rb_funcall(cBigDecimal, intern_new, 1, opt_decimal_zero);
242
242
  }else{
243
243
  val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new(row[i], fieldLengths[i]));
@@ -392,7 +392,8 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
392
392
  ID db_timezone, app_timezone, dbTz, appTz;
393
393
  mysql2_result_wrapper * wrapper;
394
394
  unsigned long i;
395
- int symbolizeKeys = 0, asArray = 0, castBool = 0, cacheRows = 1, cast = 1;
395
+ int symbolizeKeys = 0, asArray = 0, castBool = 0, cacheRows = 1, cast = 1, streaming = 0;
396
+ MYSQL_FIELD * fields = NULL;
396
397
 
397
398
  GetMysql2Result(self, wrapper);
398
399
 
@@ -423,6 +424,14 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
423
424
  cast = 0;
424
425
  }
425
426
 
427
+ if(rb_hash_aref(opts, sym_stream) == Qtrue) {
428
+ streaming = 1;
429
+ }
430
+
431
+ if(streaming && cacheRows) {
432
+ rb_warn("cacheRows is ignored if streaming is true");
433
+ }
434
+
426
435
  dbTz = rb_hash_aref(opts, sym_database_timezone);
427
436
  if (dbTz == sym_local) {
428
437
  db_timezone = intern_local;
@@ -445,49 +454,82 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
445
454
  }
446
455
 
447
456
  if (wrapper->lastRowProcessed == 0) {
448
- wrapper->numberOfRows = mysql_num_rows(wrapper->result);
449
- if (wrapper->numberOfRows == 0) {
457
+ if(streaming) {
458
+ // We can't get number of rows if we're streaming,
459
+ // until we've finished fetching all rows
460
+ wrapper->numberOfRows = 0;
450
461
  wrapper->rows = rb_ary_new();
451
- return wrapper->rows;
462
+ } else {
463
+ wrapper->numberOfRows = mysql_num_rows(wrapper->result);
464
+ if (wrapper->numberOfRows == 0) {
465
+ wrapper->rows = rb_ary_new();
466
+ return wrapper->rows;
467
+ }
468
+ wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
452
469
  }
453
- wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
454
470
  }
455
471
 
456
- if (cacheRows && wrapper->lastRowProcessed == wrapper->numberOfRows) {
457
- // we've already read the entire dataset from the C result into our
458
- // internal array. Lets hand that over to the user since it's ready to go
459
- for (i = 0; i < wrapper->numberOfRows; i++) {
460
- rb_yield(rb_ary_entry(wrapper->rows, i));
461
- }
462
- } else {
463
- unsigned long rowsProcessed = 0;
464
- rowsProcessed = RARRAY_LEN(wrapper->rows);
465
- for (i = 0; i < wrapper->numberOfRows; i++) {
472
+ if (streaming) {
473
+ if(!wrapper->streamingComplete) {
466
474
  VALUE row;
467
- if (cacheRows && i < rowsProcessed) {
468
- row = rb_ary_entry(wrapper->rows, i);
469
- } else {
470
- row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool, cast);
471
- if (cacheRows) {
472
- rb_ary_store(wrapper->rows, i, row);
475
+
476
+ fields = mysql_fetch_fields(wrapper->result);
477
+
478
+ do {
479
+ row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool, cast, fields);
480
+
481
+ if (block != Qnil && row != Qnil) {
482
+ rb_yield(row);
483
+ wrapper->lastRowProcessed++;
473
484
  }
474
- wrapper->lastRowProcessed++;
485
+ } while(row != Qnil);
486
+
487
+ rb_mysql_result_free_result(wrapper);
488
+
489
+ wrapper->numberOfRows = wrapper->lastRowProcessed;
490
+ wrapper->streamingComplete = 1;
491
+ } else {
492
+ rb_raise(cMysql2Error, "You have already fetched all the rows for this query and streaming is true. (to reiterate you must requery).");
493
+ }
494
+ } else {
495
+ if (cacheRows && wrapper->lastRowProcessed == wrapper->numberOfRows) {
496
+ // we've already read the entire dataset from the C result into our
497
+ // internal array. Lets hand that over to the user since it's ready to go
498
+ for (i = 0; i < wrapper->numberOfRows; i++) {
499
+ rb_yield(rb_ary_entry(wrapper->rows, i));
475
500
  }
501
+ } else {
502
+ unsigned long rowsProcessed = 0;
503
+ rowsProcessed = RARRAY_LEN(wrapper->rows);
504
+ fields = mysql_fetch_fields(wrapper->result);
505
+
506
+ for (i = 0; i < wrapper->numberOfRows; i++) {
507
+ VALUE row;
508
+ if (cacheRows && i < rowsProcessed) {
509
+ row = rb_ary_entry(wrapper->rows, i);
510
+ } else {
511
+ row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool, cast, fields);
512
+ if (cacheRows) {
513
+ rb_ary_store(wrapper->rows, i, row);
514
+ }
515
+ wrapper->lastRowProcessed++;
516
+ }
476
517
 
477
- if (row == Qnil) {
518
+ if (row == Qnil) {
519
+ // we don't need the mysql C dataset around anymore, peace it
520
+ rb_mysql_result_free_result(wrapper);
521
+ return Qnil;
522
+ }
523
+
524
+ if (block != Qnil) {
525
+ rb_yield(row);
526
+ }
527
+ }
528
+ if (wrapper->lastRowProcessed == wrapper->numberOfRows) {
478
529
  // we don't need the mysql C dataset around anymore, peace it
479
530
  rb_mysql_result_free_result(wrapper);
480
- return Qnil;
481
- }
482
-
483
- if (block != Qnil) {
484
- rb_yield(row);
485
531
  }
486
532
  }
487
- if (wrapper->lastRowProcessed == wrapper->numberOfRows) {
488
- // we don't need the mysql C dataset around anymore, peace it
489
- rb_mysql_result_free_result(wrapper);
490
- }
491
533
  }
492
534
 
493
535
  return wrapper->rows;
@@ -497,8 +539,15 @@ static VALUE rb_mysql_result_count(VALUE self) {
497
539
  mysql2_result_wrapper *wrapper;
498
540
 
499
541
  GetMysql2Result(self, wrapper);
500
-
501
- return INT2FIX(mysql_num_rows(wrapper->result));
542
+ if(wrapper->resultFreed) {
543
+ if (wrapper->streamingComplete){
544
+ return LONG2NUM(wrapper->numberOfRows);
545
+ } else {
546
+ return LONG2NUM(RARRAY_LEN(wrapper->rows));
547
+ }
548
+ } else {
549
+ return INT2FIX(mysql_num_rows(wrapper->result));
550
+ }
502
551
  }
503
552
 
504
553
  /* Mysql2::Result */
@@ -514,6 +563,7 @@ VALUE rb_mysql_result_to_obj(MYSQL_RES * r) {
514
563
  wrapper->fields = Qnil;
515
564
  wrapper->rows = Qnil;
516
565
  wrapper->encoding = Qnil;
566
+ wrapper->streamingComplete = 0;
517
567
  rb_obj_call_init(obj, 0, NULL);
518
568
  return obj;
519
569
  }
@@ -551,6 +601,7 @@ void init_mysql2_result() {
551
601
  sym_application_timezone = ID2SYM(rb_intern("application_timezone"));
552
602
  sym_cache_rows = ID2SYM(rb_intern("cache_rows"));
553
603
  sym_cast = ID2SYM(rb_intern("cast"));
604
+ sym_stream = ID2SYM(rb_intern("stream"));
554
605
 
555
606
  opt_decimal_zero = rb_str_new2("0.0");
556
607
  rb_global_variable(&opt_decimal_zero); //never GC
@@ -11,6 +11,7 @@ typedef struct {
11
11
  unsigned int numberOfFields;
12
12
  unsigned long numberOfRows;
13
13
  unsigned long lastRowProcessed;
14
+ char streamingComplete;
14
15
  char resultFreed;
15
16
  MYSQL_RES *result;
16
17
  } mysql2_result_wrapper;
@@ -16,6 +16,22 @@ module Mysql2
16
16
  end
17
17
 
18
18
  if defined?(ActiveRecord::VERSION::STRING) && ActiveRecord::VERSION::STRING < "3.1"
19
- puts "WARNING: This version of mysql2 (#{Mysql2::VERSION}) doesn't ship with the ActiveRecord adapter bundled anymore as it's now part of Rails 3.1"
20
- puts "WARNING: Please use the 0.2.x releases if you plan on using it in Rails <= 3.0.x"
19
+ warn "============= WARNING FROM mysql2 ============="
20
+ warn "This version of mysql2 (#{Mysql2::VERSION}) doesn't ship with the ActiveRecord adapter."
21
+ warn "In Rails version 3.1.0 and up, the mysql2 ActiveRecord adapter is included with rails."
22
+ warn "If you want to use the mysql2 gem with Rails <= 3.0.x, please use the latest mysql2 in the 0.2.x series."
23
+ warn "============= END WARNING FROM mysql2 ============="
24
+ end
25
+
26
+ # For holding utility methods
27
+ module Mysql2::Util
28
+
29
+ #
30
+ # Rekey a string-keyed hash with equivalent symbols.
31
+ #
32
+ def self.key_hash_as_symbols(hash)
33
+ return nil unless hash
34
+ Hash[hash.map { |k,v| [k.to_sym, v] }]
35
+ end
36
+
21
37
  end
@@ -14,31 +14,36 @@ module Mysql2
14
14
  }
15
15
 
16
16
  def initialize(opts = {})
17
+ opts = Mysql2::Util.key_hash_as_symbols( opts )
17
18
  @query_options = @@default_query_options.dup
18
19
  @query_options.merge! opts
19
20
 
20
- init_connection
21
+ initialize_ext
21
22
 
22
- [:reconnect, :connect_timeout].each do |key|
23
+ # Set MySQL connection options (each one is a call to mysql_options())
24
+ [:reconnect, :connect_timeout, :local_infile, :read_timeout].each do |key|
23
25
  next unless opts.key?(key)
24
26
  send(:"#{key}=", opts[key])
25
27
  end
28
+
26
29
  # force the encoding to utf8
27
30
  self.charset_name = opts[:encoding] || 'utf8'
28
31
 
29
- @read_timeout = opts[:read_timeout]
30
- if @read_timeout and @read_timeout < 0
31
- raise Mysql2::Error, "read_timeout must be a positive integer, you passed #{@read_timeout}"
32
- end
33
-
34
32
  ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher))
33
+
34
+ if [:user,:pass,:hostname,:dbname,:db,:sock].any?{|k| @query_options.has_key?(k) }
35
+ warn "============= WARNING FROM mysql2 ============="
36
+ warn "The options :user, :pass, :hostname, :dbname, :db, and :sock will be deprecated at some point in the future."
37
+ warn "Instead, please use :username, :password, :host, 'localhost', :port, :database, :socket, :flags for the options."
38
+ warn "============= END WARNING FROM mysql2 ========="
39
+ end
35
40
 
36
- user = opts[:username]
37
- pass = opts[:password]
38
- host = opts[:host] || 'localhost'
41
+ user = opts[:username] || opts[:user]
42
+ pass = opts[:password] || opts[:pass]
43
+ host = opts[:host] || opts[:hostname] || 'localhost'
39
44
  port = opts[:port] || 3306
40
- database = opts[:database]
41
- socket = opts[:socket]
45
+ database = opts[:database] || opts[:dbname] || opts[:db]
46
+ socket = opts[:socket] || opts[:sock]
42
47
  flags = opts[:flags] ? opts[:flags] | @query_options[:connect_flags] : @query_options[:connect_flags]
43
48
 
44
49
  connect user, pass, host, port, database, socket, flags
@@ -87,6 +92,7 @@ module Mysql2
87
92
  "ucs2" => Encoding::UTF_16BE,
88
93
  "ujis" => Encoding::EucJP_ms,
89
94
  "utf8" => Encoding::UTF_8,
95
+ "utf8mb4" => Encoding::UTF_8,
90
96
  }
91
97
 
92
98
  MYSQL_CHARSET_MAP = {
@@ -134,6 +140,8 @@ module Mysql2
134
140
  42 => {:name => "latin7", :collation => "latin7_general_cs"},
135
141
  43 => {:name => "macce", :collation => "macce_bin"},
136
142
  44 => {:name => "cp1250", :collation => "cp1250_croatian_ci"},
143
+ 45 => {:name => "utf8mb4", :collation => "utf8mb4_general_ci"},
144
+ 46 => {:name => "utf8mb4", :collation => "utf8mb4_bin"},
137
145
  47 => {:name => "latin1", :collation => "latin1_bin"},
138
146
  48 => {:name => "latin1", :collation => "latin1_general_ci"},
139
147
  49 => {:name => "latin1", :collation => "latin1_general_cs"},
@@ -218,6 +226,25 @@ module Mysql2
218
226
  208 => {:name => "utf8", :collation => "utf8_persian_ci"},
219
227
  209 => {:name => "utf8", :collation => "utf8_esperanto_ci"},
220
228
  210 => {:name => "utf8", :collation => "utf8_hungarian_ci"},
229
+ 224 => {:name => "utf8mb4", :collation => "utf8mb4_unicode_ci"},
230
+ 225 => {:name => "utf8mb4", :collation => "utf8mb4_icelandic_ci"},
231
+ 226 => {:name => "utf8mb4", :collation => "utf8mb4_latvian_ci"},
232
+ 227 => {:name => "utf8mb4", :collation => "utf8mb4_romanian_ci"},
233
+ 228 => {:name => "utf8mb4", :collation => "utf8mb4_slovenian_ci"},
234
+ 229 => {:name => "utf8mb4", :collation => "utf8mb4_polish_ci"},
235
+ 230 => {:name => "utf8mb4", :collation => "utf8mb4_estonian_ci"},
236
+ 231 => {:name => "utf8mb4", :collation => "utf8mb4_spanish_ci"},
237
+ 232 => {:name => "utf8mb4", :collation => "utf8mb4_swedish_ci"},
238
+ 233 => {:name => "utf8mb4", :collation => "utf8mb4_turkish_ci"},
239
+ 234 => {:name => "utf8mb4", :collation => "utf8mb4_czech_ci"},
240
+ 235 => {:name => "utf8mb4", :collation => "utf8mb4_danish_ci"},
241
+ 236 => {:name => "utf8mb4", :collation => "utf8mb4_lithuanian_ci"},
242
+ 237 => {:name => "utf8mb4", :collation => "utf8mb4_slovak_ci"},
243
+ 238 => {:name => "utf8mb4", :collation => "utf8mb4_spanish2_ci"},
244
+ 239 => {:name => "utf8mb4", :collation => "utf8mb4_roman_ci"},
245
+ 240 => {:name => "utf8mb4", :collation => "utf8mb4_persian_ci"},
246
+ 241 => {:name => "utf8mb4", :collation => "utf8mb4_esperanto_ci"},
247
+ 242 => {:name => "utf8mb4", :collation => "utf8mb4_hungarian_ci"},
221
248
  254 => {:name => "utf8", :collation => "utf8_general_cs"}
222
249
  }
223
250
 
@@ -15,18 +15,28 @@ module Mysql2
15
15
  def notify_readable
16
16
  detach
17
17
  begin
18
- @deferable.succeed(@client.async_result)
18
+ result = @client.async_result
19
19
  rescue Exception => e
20
20
  @deferable.fail(e)
21
+ else
22
+ @deferable.succeed(result)
21
23
  end
22
24
  end
23
25
  end
24
26
 
27
+ def close(*args)
28
+ if @watch
29
+ @watch.detach
30
+ end
31
+ super(*args)
32
+ end
33
+
25
34
  def query(sql, opts={})
26
35
  if ::EM.reactor_running?
27
36
  super(sql, opts.merge(:async => true))
28
37
  deferable = ::EM::DefaultDeferrable.new
29
- ::EM.watch(self.socket, Watcher, self, deferable).notify_readable = true
38
+ @watch = ::EM.watch(self.socket, Watcher, self, deferable)
39
+ @watch.notify_readable = true
30
40
  deferable
31
41
  else
32
42
  super(sql, opts)
@@ -34,4 +44,4 @@ module Mysql2
34
44
  end
35
45
  end
36
46
  end
37
- end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module Mysql2
2
- VERSION = "0.3.11"
2
+ VERSION = "0.3.12b1"
3
3
  end
@@ -0,0 +1,11 @@
1
+ root:
2
+ host: localhost
3
+ username: root
4
+ password:
5
+ database: test
6
+
7
+ user:
8
+ host: localhost
9
+ username: LOCALUSERNAME
10
+ password:
11
+ database: mysql2_test
@@ -8,14 +8,14 @@ begin
8
8
  it "should support async queries" do
9
9
  results = []
10
10
  EM.run do
11
- client1 = Mysql2::EM::Client.new
11
+ client1 = Mysql2::EM::Client.new DatabaseCredentials['root']
12
12
  defer1 = client1.query "SELECT sleep(0.1) as first_query"
13
13
  defer1.callback do |result|
14
14
  results << result.first
15
15
  EM.stop_event_loop
16
16
  end
17
17
 
18
- client2 = Mysql2::EM::Client.new
18
+ client2 = Mysql2::EM::Client.new DatabaseCredentials['root']
19
19
  defer2 = client2.query "SELECT sleep(0.025) second_query"
20
20
  defer2.callback do |result|
21
21
  results << result.first
@@ -29,7 +29,7 @@ begin
29
29
  it "should support queries in callbacks" do
30
30
  results = []
31
31
  EM.run do
32
- client = Mysql2::EM::Client.new
32
+ client = Mysql2::EM::Client.new DatabaseCredentials['root']
33
33
  defer1 = client.query "SELECT sleep(0.025) as first_query"
34
34
  defer1.callback do |result|
35
35
  results << result.first
@@ -44,6 +44,66 @@ begin
44
44
  results[0].keys.should include("first_query")
45
45
  results[1].keys.should include("second_query")
46
46
  end
47
+
48
+ it "should not swallow exceptions raised in callbacks" do
49
+ lambda {
50
+ EM.run do
51
+ client = Mysql2::EM::Client.new DatabaseCredentials['root']
52
+ defer = client.query "SELECT sleep(0.1) as first_query"
53
+ defer.callback do |result|
54
+ raise 'some error'
55
+ end
56
+ defer.errback do |err|
57
+ # This _shouldn't_ be run, but it needed to prevent the specs from
58
+ # freezing if this test fails.
59
+ EM.stop_event_loop
60
+ end
61
+ end
62
+ }.should raise_error
63
+ end
64
+
65
+ context 'when an exception is raised by the client' do
66
+ let(:client) { Mysql2::EM::Client.new DatabaseCredentials['root'] }
67
+ let(:error) { StandardError.new('some error') }
68
+ before { client.stub(:async_result).and_raise(error) }
69
+
70
+ it "should swallow exceptions raised in by the client" do
71
+ errors = []
72
+ EM.run do
73
+ defer = client.query "SELECT sleep(0.1) as first_query"
74
+ defer.callback do |result|
75
+ # This _shouldn't_ be run, but it is needed to prevent the specs from
76
+ # freezing if this test fails.
77
+ EM.stop_event_loop
78
+ end
79
+ defer.errback do |err|
80
+ errors << err
81
+ EM.stop_event_loop
82
+ end
83
+ end
84
+ errors.should == [error]
85
+ end
86
+
87
+ it "should fail the deferrable" do
88
+ callbacks_run = []
89
+ EM.run do
90
+ defer = client.query "SELECT sleep(0.025) as first_query"
91
+ EM.add_timer(0.1) do
92
+ defer.callback do |result|
93
+ callbacks_run << :callback
94
+ # This _shouldn't_ be run, but it is needed to prevent the specs from
95
+ # freezing if this test fails.
96
+ EM.stop_event_loop
97
+ end
98
+ defer.errback do |err|
99
+ callbacks_run << :errback
100
+ EM.stop_event_loop
101
+ end
102
+ end
103
+ end
104
+ callbacks_run.should == [:errback]
105
+ end
106
+ end
47
107
  end
48
108
  rescue LoadError
49
109
  puts "EventMachine not installed, skipping the specs that use it"