mysql2 0.3.17 → 0.3.20

Sign up to get free protection for your applications and to get access to all the features.
data/ext/mysql2/result.c CHANGED
@@ -50,6 +50,10 @@ static rb_encoding *binaryEncoding;
50
50
  #define MYSQL2_MIN_TIME 62171150401ULL
51
51
  #endif
52
52
 
53
+ #define GET_RESULT(obj) \
54
+ mysql2_result_wrapper *wrapper; \
55
+ Data_Get_Struct(self, mysql2_result_wrapper, wrapper);
56
+
53
57
  static VALUE cMysql2Result;
54
58
  static VALUE cBigDecimal, cDate, cDateTime;
55
59
  static VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month, opt_utc_offset;
@@ -103,9 +107,8 @@ static void *nogvl_fetch_row(void *ptr) {
103
107
  }
104
108
 
105
109
  static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int symbolize_keys) {
106
- mysql2_result_wrapper * wrapper;
107
110
  VALUE rb_field;
108
- GetMysql2Result(self, wrapper);
111
+ GET_RESULT(self);
109
112
 
110
113
  if (wrapper->fields == Qnil) {
111
114
  wrapper->numberOfFields = mysql_num_fields(wrapper->result);
@@ -193,7 +196,6 @@ static unsigned int msec_char_to_uint(char *msec_char, size_t len)
193
196
 
194
197
  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) {
195
198
  VALUE rowVal;
196
- mysql2_result_wrapper * wrapper;
197
199
  MYSQL_ROW row;
198
200
  unsigned int i = 0;
199
201
  unsigned long * fieldLengths;
@@ -202,7 +204,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
202
204
  rb_encoding *default_internal_enc;
203
205
  rb_encoding *conn_enc;
204
206
  #endif
205
- GetMysql2Result(self, wrapper);
207
+ GET_RESULT(self);
206
208
 
207
209
  #ifdef HAVE_RUBY_ENCODING_H
208
210
  default_internal_enc = rb_default_internal_encoding();
@@ -232,7 +234,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
232
234
  VALUE val = Qnil;
233
235
  enum enum_field_types type = fields[i].type;
234
236
 
235
- if(!cast) {
237
+ if (!cast) {
236
238
  if (type == MYSQL_TYPE_NULL) {
237
239
  val = Qnil;
238
240
  } else {
@@ -297,7 +299,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
297
299
  break;
298
300
  }
299
301
  msec = msec_char_to_uint(msec_char, sizeof(msec_char));
300
- val = rb_funcall(rb_cTime, db_timezone, 6, opt_time_year, opt_time_month, opt_time_month, UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec));
302
+ val = rb_funcall(rb_cTime, db_timezone, 7, opt_time_year, opt_time_month, opt_time_month, UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec));
301
303
  if (!NIL_P(app_timezone)) {
302
304
  if (app_timezone == intern_local) {
303
305
  val = rb_funcall(val, intern_localtime, 0);
@@ -413,12 +415,11 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
413
415
  }
414
416
 
415
417
  static VALUE rb_mysql_result_fetch_fields(VALUE self) {
416
- mysql2_result_wrapper * wrapper;
417
418
  unsigned int i = 0;
418
419
  short int symbolizeKeys = 0;
419
420
  VALUE defaults;
420
421
 
421
- GetMysql2Result(self, wrapper);
422
+ GET_RESULT(self);
422
423
 
423
424
  defaults = rb_iv_get(self, "@query_options");
424
425
  Check_Type(defaults, T_HASH);
@@ -443,13 +444,12 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
443
444
  static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
444
445
  VALUE defaults, opts, block;
445
446
  ID db_timezone, app_timezone, dbTz, appTz;
446
- mysql2_result_wrapper * wrapper;
447
447
  unsigned long i;
448
448
  const char * errstr;
449
- int symbolizeKeys = 0, asArray = 0, castBool = 0, cacheRows = 1, cast = 1, streaming = 0;
449
+ int symbolizeKeys, asArray, castBool, cacheRows, cast;
450
450
  MYSQL_FIELD * fields = NULL;
451
451
 
452
- GetMysql2Result(self, wrapper);
452
+ GET_RESULT(self);
453
453
 
454
454
  defaults = rb_iv_get(self, "@query_options");
455
455
  Check_Type(defaults, T_HASH);
@@ -459,32 +459,14 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
459
459
  opts = defaults;
460
460
  }
461
461
 
462
- if (rb_hash_aref(opts, sym_symbolize_keys) == Qtrue) {
463
- symbolizeKeys = 1;
464
- }
465
-
466
- if (rb_hash_aref(opts, sym_as) == sym_array) {
467
- asArray = 1;
468
- }
469
-
470
- if (rb_hash_aref(opts, sym_cast_booleans) == Qtrue) {
471
- castBool = 1;
472
- }
473
-
474
- if (rb_hash_aref(opts, sym_cache_rows) == Qfalse) {
475
- cacheRows = 0;
476
- }
477
-
478
- if (rb_hash_aref(opts, sym_cast) == Qfalse) {
479
- cast = 0;
480
- }
481
-
482
- if(rb_hash_aref(opts, sym_stream) == Qtrue) {
483
- streaming = 1;
484
- }
462
+ symbolizeKeys = RTEST(rb_hash_aref(opts, sym_symbolize_keys));
463
+ asArray = rb_hash_aref(opts, sym_as) == sym_array;
464
+ castBool = RTEST(rb_hash_aref(opts, sym_cast_booleans));
465
+ cacheRows = RTEST(rb_hash_aref(opts, sym_cache_rows));
466
+ cast = RTEST(rb_hash_aref(opts, sym_cast));
485
467
 
486
- if(streaming && cacheRows) {
487
- rb_warn("cacheRows is ignored if streaming is true");
468
+ if (wrapper->is_streaming && cacheRows) {
469
+ rb_warn(":cache_rows is ignored if :stream is true");
488
470
  }
489
471
 
490
472
  dbTz = rb_hash_aref(opts, sym_database_timezone);
@@ -508,23 +490,12 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
508
490
  app_timezone = Qnil;
509
491
  }
510
492
 
511
- if (wrapper->lastRowProcessed == 0) {
512
- if (streaming) {
513
- /* We can't get number of rows if we're streaming, */
514
- /* until we've finished fetching all rows */
515
- wrapper->numberOfRows = 0;
493
+ if (wrapper->is_streaming) {
494
+ /* When streaming, we will only yield rows, not return them. */
495
+ if (wrapper->rows == Qnil) {
516
496
  wrapper->rows = rb_ary_new();
517
- } else {
518
- wrapper->numberOfRows = mysql_num_rows(wrapper->result);
519
- if (wrapper->numberOfRows == 0) {
520
- wrapper->rows = rb_ary_new();
521
- return wrapper->rows;
522
- }
523
- wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
524
497
  }
525
- }
526
498
 
527
- if (streaming) {
528
499
  if (!wrapper->streamingComplete) {
529
500
  VALUE row;
530
501
 
@@ -532,16 +503,15 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
532
503
 
533
504
  do {
534
505
  row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool, cast, fields);
535
-
536
- if (block != Qnil && row != Qnil) {
537
- rb_yield(row);
538
- wrapper->lastRowProcessed++;
506
+ if (row != Qnil) {
507
+ wrapper->numberOfRows++;
508
+ if (block != Qnil) {
509
+ rb_yield(row);
510
+ }
539
511
  }
540
512
  } while(row != Qnil);
541
513
 
542
514
  rb_mysql_result_free_result(wrapper);
543
-
544
- wrapper->numberOfRows = wrapper->lastRowProcessed;
545
515
  wrapper->streamingComplete = 1;
546
516
 
547
517
  // Check for errors, the connection might have gone out from under us
@@ -554,6 +524,15 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
554
524
  rb_raise(cMysql2Error, "You have already fetched all the rows for this query and streaming is true. (to reiterate you must requery).");
555
525
  }
556
526
  } else {
527
+ if (wrapper->lastRowProcessed == 0) {
528
+ wrapper->numberOfRows = mysql_num_rows(wrapper->result);
529
+ if (wrapper->numberOfRows == 0) {
530
+ wrapper->rows = rb_ary_new();
531
+ return wrapper->rows;
532
+ }
533
+ wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
534
+ }
535
+
557
536
  if (cacheRows && wrapper->lastRowProcessed == wrapper->numberOfRows) {
558
537
  /* we've already read the entire dataset from the C result into our */
559
538
  /* internal array. Lets hand that over to the user since it's ready to go */
@@ -598,17 +577,19 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
598
577
  }
599
578
 
600
579
  static VALUE rb_mysql_result_count(VALUE self) {
601
- mysql2_result_wrapper *wrapper;
580
+ GET_RESULT(self);
602
581
 
603
- GetMysql2Result(self, wrapper);
604
- if(wrapper->resultFreed) {
605
- if (wrapper->streamingComplete){
606
- return LONG2NUM(wrapper->numberOfRows);
607
- } else {
608
- return LONG2NUM(RARRAY_LEN(wrapper->rows));
609
- }
582
+ if (wrapper->is_streaming) {
583
+ /* This is an unsigned long per result.h */
584
+ return ULONG2NUM(wrapper->numberOfRows);
585
+ }
586
+
587
+ if (wrapper->resultFreed) {
588
+ /* Ruby arrays have platform signed long length */
589
+ return LONG2NUM(RARRAY_LEN(wrapper->rows));
610
590
  } else {
611
- return INT2FIX(mysql_num_rows(wrapper->result));
591
+ /* MySQL returns an unsigned 64-bit long here */
592
+ return ULL2NUM(mysql_num_rows(wrapper->result));
612
593
  }
613
594
  }
614
595
 
@@ -616,6 +597,7 @@ static VALUE rb_mysql_result_count(VALUE self) {
616
597
  VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_RES *r) {
617
598
  VALUE obj;
618
599
  mysql2_result_wrapper * wrapper;
600
+
619
601
  obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper);
620
602
  wrapper->numberOfFields = 0;
621
603
  wrapper->numberOfRows = 0;
@@ -634,6 +616,10 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
634
616
 
635
617
  rb_iv_set(obj, "@query_options", options);
636
618
 
619
+ /* Options that cannot be changed in results.each(...) { |row| }
620
+ * should be processed here. */
621
+ wrapper->is_streaming = (rb_hash_aref(options, sym_stream) == Qtrue ? 1 : 0);
622
+
637
623
  return obj;
638
624
  }
639
625
 
data/ext/mysql2/result.h CHANGED
@@ -12,12 +12,11 @@ typedef struct {
12
12
  unsigned int numberOfFields;
13
13
  unsigned long numberOfRows;
14
14
  unsigned long lastRowProcessed;
15
+ char is_streaming;
15
16
  char streamingComplete;
16
17
  char resultFreed;
17
18
  MYSQL_RES *result;
18
19
  mysql_client_wrapper *client_wrapper;
19
20
  } mysql2_result_wrapper;
20
21
 
21
- #define GetMysql2Result(obj, sval) (sval = (mysql2_result_wrapper*)DATA_PTR(obj));
22
-
23
22
  #endif
data/lib/mysql2/client.rb CHANGED
@@ -82,6 +82,10 @@ module Mysql2
82
82
  info_hash
83
83
  end
84
84
 
85
+ def info
86
+ self.class.info
87
+ end
88
+
85
89
  private
86
90
  def self.local_offset
87
91
  ::Time.local(2010).utc_offset.to_r / 86400
data/lib/mysql2/em.rb CHANGED
@@ -10,6 +10,7 @@ module Mysql2
10
10
  def initialize(client, deferable)
11
11
  @client = client
12
12
  @deferable = deferable
13
+ @is_watching = true
13
14
  end
14
15
 
15
16
  def notify_readable
@@ -22,11 +23,19 @@ module Mysql2
22
23
  @deferable.succeed(result)
23
24
  end
24
25
  end
26
+
27
+ def watching?
28
+ @is_watching
29
+ end
30
+
31
+ def unbind
32
+ @is_watching = false
33
+ end
25
34
  end
26
35
 
27
36
  def close(*args)
28
37
  if @watch
29
- @watch.detach
38
+ @watch.detach if @watch.watching?
30
39
  end
31
40
  super(*args)
32
41
  end
data/lib/mysql2/error.rb CHANGED
@@ -30,7 +30,7 @@ module Mysql2
30
30
  # variable.
31
31
  #
32
32
  # See http://dev.mysql.com/doc/refman/5.5/en/charset-errors.html for
33
- # more contetx.
33
+ # more context.
34
34
  #
35
35
  # Before MySQL 5.5 error message template strings are in whatever encoding
36
36
  # is associated with the error message language.
@@ -1,3 +1,3 @@
1
1
  module Mysql2
2
- VERSION = "0.3.17"
2
+ VERSION = "0.3.20"
3
3
  end
data/lib/mysql2.rb CHANGED
@@ -3,6 +3,29 @@ require 'date'
3
3
  require 'bigdecimal'
4
4
  require 'rational' unless RUBY_VERSION >= '1.9.2'
5
5
 
6
+ # Load libmysql.dll before requiring mysql2/mysql2.so
7
+ # This gives a chance to be flexible about the load path
8
+ # Or to bomb out with a clear error message instead of a linker crash
9
+ if RUBY_PLATFORM =~ /mswin|mingw/
10
+ dll_path = if ENV['RUBY_MYSQL2_LIBMYSQL_DLL']
11
+ # If this environment variable is set, it overrides any other paths
12
+ # The user is advised to use backslashes not forward slashes
13
+ ENV['RUBY_MYSQL2_LIBMYSQL_DLL'].dup
14
+ elsif File.exist?(File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)))
15
+ # Use vendor/libmysql.dll if it exists, convert slashes for Win32 LoadLibrary
16
+ File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)).gsub('/', '\\')
17
+ else
18
+ # This will use default / system library paths
19
+ 'libmysql.dll'
20
+ end
21
+
22
+ require 'Win32API'
23
+ LoadLibrary = Win32API.new('Kernel32', 'LoadLibrary', ['P'], 'I')
24
+ if 0 == LoadLibrary.call(dll_path)
25
+ abort "Failed to load libmysql.dll from #{dll_path}"
26
+ end
27
+ end
28
+
6
29
  require 'mysql2/version' unless defined? Mysql2::VERSION
7
30
  require 'mysql2/error'
8
31
  require 'mysql2/mysql2'
data/spec/em/em_spec.rb CHANGED
@@ -108,6 +108,27 @@ begin
108
108
  callbacks_run.should == [:errback]
109
109
  end
110
110
  end
111
+
112
+ it "should not raise error when closing client with no query running" do
113
+ callbacks_run = []
114
+ EM.run do
115
+ client = Mysql2::EM::Client.new DatabaseCredentials['root']
116
+ defer = client.query("select sleep(0.025)")
117
+ defer.callback do |result|
118
+ callbacks_run << :callback
119
+ end
120
+ defer.errback do |err|
121
+ callbacks_run << :errback
122
+ end
123
+ EM.add_timer(0.1) do
124
+ callbacks_run.should == [:callback]
125
+ lambda {
126
+ client.close
127
+ }.should_not raise_error(/invalid binding to detach/)
128
+ EM.stop_event_loop
129
+ end
130
+ end
131
+ end
111
132
  end
112
133
  rescue LoadError
113
134
  puts "EventMachine not installed, skipping the specs that use it"
@@ -66,12 +66,13 @@ describe Mysql2::Client do
66
66
  end
67
67
  end
68
68
  client = klient.new
69
- (client.connect_args.last[6] & (Mysql2::Client::REMEMBER_OPTIONS |
70
- Mysql2::Client::LONG_PASSWORD |
71
- Mysql2::Client::LONG_FLAG |
72
- Mysql2::Client::TRANSACTIONS |
73
- Mysql2::Client::PROTOCOL_41 |
74
- Mysql2::Client::SECURE_CONNECTION)).should be_true
69
+ client_flags = Mysql2::Client::REMEMBER_OPTIONS |
70
+ Mysql2::Client::LONG_PASSWORD |
71
+ Mysql2::Client::LONG_FLAG |
72
+ Mysql2::Client::TRANSACTIONS |
73
+ Mysql2::Client::PROTOCOL_41 |
74
+ Mysql2::Client::SECURE_CONNECTION
75
+ client.connect_args.last[6].should eql(client_flags)
75
76
  end
76
77
 
77
78
  it "should execute init command" do
@@ -564,7 +565,7 @@ describe Mysql2::Client do
564
565
  end
565
566
 
566
567
  it "should raise an exception when one of multiple statements fails" do
567
- result = @multi_client.query("SELECT 1 as 'set_1'; SELECT * FROM invalid_table_name;SELECT 2 as 'set_2';")
568
+ result = @multi_client.query("SELECT 1 AS 'set_1'; SELECT * FROM invalid_table_name; SELECT 2 AS 'set_2';")
568
569
  result.first['set_1'].should be(1)
569
570
  lambda {
570
571
  @multi_client.next_result
@@ -573,7 +574,7 @@ describe Mysql2::Client do
573
574
  end
574
575
 
575
576
  it "returns multiple result sets" do
576
- @multi_client.query( "select 1 as 'set_1'; select 2 as 'set_2'").first.should eql({ 'set_1' => 1 })
577
+ @multi_client.query("SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'").first.should eql({ 'set_1' => 1 })
577
578
 
578
579
  @multi_client.next_result.should be_true
579
580
  @multi_client.store_result.first.should eql({ 'set_2' => 2 })
@@ -582,12 +583,12 @@ describe Mysql2::Client do
582
583
  end
583
584
 
584
585
  it "does not interfere with other statements" do
585
- @multi_client.query( "select 1 as 'set_1'; select 2 as 'set_2'")
586
+ @multi_client.query("SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'")
586
587
  while( @multi_client.next_result )
587
588
  @multi_client.store_result
588
589
  end
589
590
 
590
- @multi_client.query( "select 3 as 'next'").first.should == { 'next' => 3 }
591
+ @multi_client.query("SELECT 3 AS 'next'").first.should == { 'next' => 3 }
591
592
  end
592
593
 
593
594
  it "will raise on query if there are outstanding results to read" do
@@ -606,7 +607,7 @@ describe Mysql2::Client do
606
607
  end
607
608
 
608
609
  it "#more_results? should work" do
609
- @multi_client.query( "select 1 as 'set_1'; select 2 as 'set_2'")
610
+ @multi_client.query("SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'")
610
611
  @multi_client.more_results?.should be_true
611
612
 
612
613
  @multi_client.next_result
@@ -614,6 +615,21 @@ describe Mysql2::Client do
614
615
 
615
616
  @multi_client.more_results?.should be_false
616
617
  end
618
+
619
+ it "#more_results? should work with stored procedures" do
620
+ @multi_client.query("DROP PROCEDURE IF EXISTS test_proc")
621
+ @multi_client.query("CREATE PROCEDURE test_proc() BEGIN SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'; END")
622
+ @multi_client.query("CALL test_proc()").first.should eql({ 'set_1' => 1 })
623
+ @multi_client.more_results?.should be_true
624
+
625
+ @multi_client.next_result
626
+ @multi_client.store_result.first.should eql({ 'set_2' => 2 })
627
+
628
+ @multi_client.next_result
629
+ @multi_client.store_result.should be_nil # this is the result from CALL itself
630
+
631
+ @multi_client.more_results?.should be_false
632
+ end
617
633
  end
618
634
  end
619
635
 
@@ -700,6 +716,19 @@ describe Mysql2::Client do
700
716
  @client.escape ""
701
717
  }.should raise_error(Mysql2::Error)
702
718
  end
719
+
720
+ context 'when mysql encoding is not utf8' do
721
+ before { pending('Encoding is undefined') unless defined?(Encoding) }
722
+
723
+ let(:client) { Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "ujis")) }
724
+
725
+ it 'should return a internal encoding string if Encoding.default_internal is set' do
726
+ with_internal_encoding Encoding::UTF_8 do
727
+ client.escape("\u{30C6}\u{30B9}\u{30C8}").should eql("\u{30C6}\u{30B9}\u{30C8}")
728
+ client.escape("\u{30C6}'\u{30B9}\"\u{30C8}").should eql("\u{30C6}\\'\u{30B9}\\\"\u{30C8}")
729
+ end
730
+ end
731
+ end
703
732
  end
704
733
 
705
734
  it "should respond to #info" do
@@ -715,26 +744,21 @@ describe Mysql2::Client do
715
744
  info[:version].class.should eql(String)
716
745
  end
717
746
 
718
- if defined? Encoding
719
- context "strings returned by #info" do
720
- it "should default to the connection's encoding if Encoding.default_internal is nil" do
721
- with_internal_encoding nil do
722
- @client.info[:version].encoding.should eql(Encoding.find('utf-8'))
747
+ context "strings returned by #info" do
748
+ before { pending('Encoding is undefined') unless defined?(Encoding) }
723
749
 
724
- client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii'))
725
- client2.info[:version].encoding.should eql(Encoding.find('us-ascii'))
726
- end
727
- end
750
+ it "should be tagged as ascii" do
751
+ @client.info[:version].encoding.should eql(Encoding::US_ASCII)
752
+ @client.info[:header_version].encoding.should eql(Encoding::US_ASCII)
753
+ end
754
+ end
728
755
 
729
- it "should use Encoding.default_internal" do
730
- with_internal_encoding 'utf-8' do
731
- @client.info[:version].encoding.should eql(Encoding.default_internal)
732
- end
756
+ context "strings returned by .info" do
757
+ before { pending('Encoding is undefined') unless defined?(Encoding) }
733
758
 
734
- with_internal_encoding 'us-ascii' do
735
- @client.info[:version].encoding.should eql(Encoding.default_internal)
736
- end
737
- end
759
+ it "should be tagged as ascii" do
760
+ Mysql2::Client.info[:version].encoding.should eql(Encoding::US_ASCII)
761
+ Mysql2::Client.info[:header_version].encoding.should eql(Encoding::US_ASCII)
738
762
  end
739
763
  end
740
764
 
@@ -6,6 +6,14 @@ describe Mysql2::Result do
6
6
  @result = @client.query "SELECT 1"
7
7
  end
8
8
 
9
+ it "should raise a TypeError exception when it doesn't wrap a result set" do
10
+ r = Mysql2::Result.new
11
+ expect { r.count }.to raise_error(TypeError)
12
+ expect { r.fields }.to raise_error(TypeError)
13
+ expect { r.size }.to raise_error(TypeError)
14
+ expect { r.each }.to raise_error(TypeError)
15
+ end
16
+
9
17
  it "should have included Enumerable" do
10
18
  Mysql2::Result.ancestors.include?(Enumerable).should be_true
11
19
  end
@@ -107,18 +115,19 @@ describe Mysql2::Result do
107
115
 
108
116
  context "streaming" do
109
117
  it "should maintain a count while streaming" do
110
- result = @client.query('SELECT 1')
111
-
112
- result.count.should eql(1)
118
+ result = @client.query('SELECT 1', :stream => true, :cache_rows => false)
119
+ result.count.should eql(0)
113
120
  result.each.to_a
114
121
  result.count.should eql(1)
115
122
  end
116
123
 
117
- it "should set the actual count of rows after streaming" do
118
- result = @client.query("SELECT * FROM mysql2_test", :stream => true, :cache_rows => false)
124
+ it "should retain the count when mixing first and each" do
125
+ result = @client.query("SELECT 1 UNION SELECT 2", :stream => true, :cache_rows => false)
119
126
  result.count.should eql(0)
120
- result.each {|r| }
127
+ result.first
121
128
  result.count.should eql(1)
129
+ result.each.to_a
130
+ result.count.should eql(2)
122
131
  end
123
132
 
124
133
  it "should not yield nil at the end of streaming" do
@@ -136,7 +145,7 @@ describe Mysql2::Result do
136
145
  it "should raise an exception if streaming ended due to a timeout" do
137
146
  # Create an extra client instance, since we're going to time it out
138
147
  client = Mysql2::Client.new DatabaseCredentials['root']
139
- client.query "CREATE TEMPORARY TABLE streamingTest (val BINARY(255))"
148
+ client.query "CREATE TEMPORARY TABLE streamingTest (val BINARY(255)) ENGINE=MEMORY"
140
149
 
141
150
  # Insert enough records to force the result set into multiple reads
142
151
  # (the BINARY type is used simply because it forces full width results)