mysql2 0.3.17 → 0.3.20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/README.md +34 -19
- data/ext/mysql2/client.c +64 -61
- data/ext/mysql2/extconf.rb +99 -35
- data/ext/mysql2/result.c +51 -65
- data/ext/mysql2/result.h +1 -2
- data/lib/mysql2/client.rb +4 -0
- data/lib/mysql2/em.rb +10 -1
- data/lib/mysql2/error.rb +1 -1
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +23 -0
- data/spec/em/em_spec.rb +21 -0
- data/spec/mysql2/client_spec.rb +52 -28
- data/spec/mysql2/result_spec.rb +16 -7
- data/support/libmysql.def +219 -0
- metadata +6 -19
- data/MIT-LICENSE +0 -20
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
|
-
|
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
|
-
|
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,
|
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
|
-
|
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
|
449
|
+
int symbolizeKeys, asArray, castBool, cacheRows, cast;
|
450
450
|
MYSQL_FIELD * fields = NULL;
|
451
451
|
|
452
|
-
|
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
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
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(
|
487
|
-
rb_warn("
|
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->
|
512
|
-
|
513
|
-
|
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
|
-
|
537
|
-
|
538
|
-
|
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
|
-
|
580
|
+
GET_RESULT(self);
|
602
581
|
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
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
|
-
|
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
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
|
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.
|
data/lib/mysql2/version.rb
CHANGED
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"
|
data/spec/mysql2/client_spec.rb
CHANGED
@@ -66,12 +66,13 @@ describe Mysql2::Client do
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
client = klient.new
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
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(
|
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(
|
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(
|
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(
|
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
|
-
|
719
|
-
|
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
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
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
|
-
|
730
|
-
|
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
|
-
|
735
|
-
|
736
|
-
|
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
|
|
data/spec/mysql2/result_spec.rb
CHANGED
@@ -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
|
118
|
-
result = @client.query("SELECT
|
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.
|
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)
|