mysql2 0.3.1 → 0.5.2

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.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -151
  3. data/LICENSE +21 -0
  4. data/README.md +634 -0
  5. data/examples/eventmachine.rb +1 -3
  6. data/examples/threaded.rb +5 -9
  7. data/ext/mysql2/client.c +1154 -342
  8. data/ext/mysql2/client.h +20 -33
  9. data/ext/mysql2/extconf.rb +229 -37
  10. data/ext/mysql2/infile.c +122 -0
  11. data/ext/mysql2/infile.h +1 -0
  12. data/ext/mysql2/mysql2_ext.c +3 -1
  13. data/ext/mysql2/mysql2_ext.h +18 -16
  14. data/ext/mysql2/mysql_enc_name_to_ruby.h +168 -0
  15. data/ext/mysql2/mysql_enc_to_ruby.h +259 -0
  16. data/ext/mysql2/result.c +708 -191
  17. data/ext/mysql2/result.h +15 -6
  18. data/ext/mysql2/statement.c +602 -0
  19. data/ext/mysql2/statement.h +17 -0
  20. data/ext/mysql2/wait_for_single_fd.h +37 -0
  21. data/lib/mysql2.rb +69 -7
  22. data/lib/mysql2/client.rb +126 -211
  23. data/lib/mysql2/console.rb +5 -0
  24. data/lib/mysql2/em.rb +24 -8
  25. data/lib/mysql2/error.rb +93 -8
  26. data/lib/mysql2/field.rb +3 -0
  27. data/lib/mysql2/result.rb +2 -0
  28. data/lib/mysql2/statement.rb +11 -0
  29. data/lib/mysql2/version.rb +2 -2
  30. data/spec/configuration.yml.example +11 -0
  31. data/spec/em/em_spec.rb +101 -15
  32. data/spec/my.cnf.example +9 -0
  33. data/spec/mysql2/client_spec.rb +874 -232
  34. data/spec/mysql2/error_spec.rb +55 -46
  35. data/spec/mysql2/result_spec.rb +306 -154
  36. data/spec/mysql2/statement_spec.rb +712 -0
  37. data/spec/spec_helper.rb +103 -57
  38. data/spec/ssl/ca-cert.pem +17 -0
  39. data/spec/ssl/ca-key.pem +27 -0
  40. data/spec/ssl/ca.cnf +22 -0
  41. data/spec/ssl/cert.cnf +22 -0
  42. data/spec/ssl/client-cert.pem +17 -0
  43. data/spec/ssl/client-key.pem +27 -0
  44. data/spec/ssl/client-req.pem +15 -0
  45. data/spec/ssl/gen_certs.sh +48 -0
  46. data/spec/ssl/pkcs8-client-key.pem +28 -0
  47. data/spec/ssl/pkcs8-server-key.pem +28 -0
  48. data/spec/ssl/server-cert.pem +17 -0
  49. data/spec/ssl/server-key.pem +27 -0
  50. data/spec/ssl/server-req.pem +15 -0
  51. data/spec/test_data +1 -0
  52. data/support/5072E1F5.asc +432 -0
  53. data/support/libmysql.def +219 -0
  54. data/support/mysql_enc_to_ruby.rb +81 -0
  55. data/support/ruby_enc_to_mysql.rb +61 -0
  56. metadata +82 -188
  57. data/.gitignore +0 -12
  58. data/.rspec +0 -2
  59. data/.rvmrc +0 -1
  60. data/Gemfile +0 -3
  61. data/MIT-LICENSE +0 -20
  62. data/README.rdoc +0 -257
  63. data/Rakefile +0 -5
  64. data/benchmark/active_record.rb +0 -51
  65. data/benchmark/active_record_threaded.rb +0 -42
  66. data/benchmark/allocations.rb +0 -33
  67. data/benchmark/escape.rb +0 -36
  68. data/benchmark/query_with_mysql_casting.rb +0 -80
  69. data/benchmark/query_without_mysql_casting.rb +0 -47
  70. data/benchmark/sequel.rb +0 -37
  71. data/benchmark/setup_db.rb +0 -119
  72. data/benchmark/threaded.rb +0 -44
  73. data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +0 -64
  74. data/lib/active_record/fiber_patches.rb +0 -104
  75. data/lib/mysql2/em_fiber.rb +0 -31
  76. data/mysql2.gemspec +0 -32
  77. data/spec/em/em_fiber_spec.rb +0 -22
  78. data/tasks/benchmarks.rake +0 -20
  79. data/tasks/compile.rake +0 -71
  80. data/tasks/rspec.rake +0 -16
  81. data/tasks/vendor_mysql.rake +0 -40
@@ -1,68 +1,77 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
- describe Mysql2::Error do
5
- before(:each) do
6
- @client = Mysql2::Client.new :encoding => "utf8"
3
+ RSpec.describe Mysql2::Error do
4
+ let(:error) do
7
5
  begin
8
6
  @client.query("HAHAHA")
9
7
  rescue Mysql2::Error => e
10
- @error = e
8
+ error = e
11
9
  end
12
10
 
13
- @client2 = Mysql2::Client.new :encoding => "big5"
14
- begin
15
- @client2.query("HAHAHA")
16
- rescue Mysql2::Error => e
17
- @error2 = e
18
- end
11
+ error
19
12
  end
20
13
 
21
- it "should respond to #error_number" do
22
- @error.should respond_to(:error_number)
23
- end
14
+ it "responds to error_number and sql_state, with aliases" do
15
+ expect(error).to respond_to(:error_number)
16
+ expect(error).to respond_to(:sql_state)
24
17
 
25
- it "should respond to #sql_state" do
26
- @error.should respond_to(:sql_state)
18
+ # Mysql gem compatibility
19
+ expect(error).to respond_to(:errno)
20
+ expect(error).to respond_to(:error)
27
21
  end
28
22
 
29
- # Mysql gem compatibility
30
- it "should alias #error_number to #errno" do
31
- @error.should respond_to(:errno)
32
- end
33
-
34
- it "should alias #message to #error" do
35
- @error.should respond_to(:error)
36
- end
23
+ context 'encoding' do
24
+ let(:valid_utf8) { '造字' }
25
+ let(:error) do
26
+ begin
27
+ @client.query(valid_utf8)
28
+ rescue Mysql2::Error => e
29
+ e
30
+ end
31
+ end
37
32
 
38
- if RUBY_VERSION =~ /1.9/
39
- it "#message encoding should match the connection's encoding, or Encoding.default_internal if set" do
40
- if Encoding.default_internal.nil?
41
- @error.message.encoding.should eql(@client.encoding)
42
- @error2.message.encoding.should eql(@client2.encoding)
43
- else
44
- @error.message.encoding.should eql(Encoding.default_internal)
45
- @error2.message.encoding.should eql(Encoding.default_internal)
33
+ let(:invalid_utf8) { ["e5c67d1f"].pack('H*').force_encoding(Encoding::UTF_8) }
34
+ let(:bad_err) do
35
+ begin
36
+ @client.query(invalid_utf8)
37
+ rescue Mysql2::Error => e
38
+ e
46
39
  end
47
40
  end
48
41
 
49
- it "#error encoding should match the connection's encoding, or Encoding.default_internal if set" do
50
- if Encoding.default_internal.nil?
51
- @error.error.encoding.should eql(@client.encoding)
52
- @error2.error.encoding.should eql(@client2.encoding)
53
- else
54
- @error.error.encoding.should eql(Encoding.default_internal)
55
- @error2.error.encoding.should eql(Encoding.default_internal)
42
+ before do
43
+ # sanity check
44
+ expect(valid_utf8.encoding).to eql(Encoding::UTF_8)
45
+ expect(valid_utf8).to be_valid_encoding
46
+
47
+ expect(invalid_utf8.encoding).to eql(Encoding::UTF_8)
48
+ expect(invalid_utf8).to_not be_valid_encoding
49
+ end
50
+
51
+ it "returns error messages as UTF-8 by default" do
52
+ with_internal_encoding nil do
53
+ expect(error.message.encoding).to eql(Encoding::UTF_8)
54
+ expect(error.message).to be_valid_encoding
55
+
56
+ expect(bad_err.message.encoding).to eql(Encoding::UTF_8)
57
+ expect(bad_err.message).to be_valid_encoding
58
+
59
+ expect(bad_err.message).to include("??}\u001F")
56
60
  end
57
61
  end
58
62
 
59
- it "#sql_state encoding should match the connection's encoding, or Encoding.default_internal if set" do
60
- if Encoding.default_internal.nil?
61
- @error.sql_state.encoding.should eql(@client.encoding)
62
- @error2.sql_state.encoding.should eql(@client2.encoding)
63
- else
64
- @error.sql_state.encoding.should eql(Encoding.default_internal)
65
- @error2.sql_state.encoding.should eql(Encoding.default_internal)
63
+ it "returns sql state as ASCII" do
64
+ expect(error.sql_state.encoding).to eql(Encoding::US_ASCII)
65
+ expect(error.sql_state).to be_valid_encoding
66
+ end
67
+
68
+ it "returns error messages and sql state in Encoding.default_internal if set" do
69
+ with_internal_encoding Encoding::UTF_16LE do
70
+ expect(error.message.encoding).to eql(Encoding.default_internal)
71
+ expect(error.message).to be_valid_encoding
72
+
73
+ expect(bad_err.message.encoding).to eql(Encoding.default_internal)
74
+ expect(bad_err.message).to be_valid_encoding
66
75
  end
67
76
  end
68
77
  end
@@ -1,271 +1,404 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
- describe Mysql2::Result do
3
+ RSpec.describe Mysql2::Result do
5
4
  before(:each) do
6
- @client = Mysql2::Client.new :host => "localhost", :username => "root", :database => 'test'
5
+ @result = @client.query "SELECT 1"
7
6
  end
8
7
 
9
- before(:each) do
10
- @result = @client.query "SELECT 1"
8
+ it "should raise a TypeError exception when it doesn't wrap a result set" do
9
+ r = Mysql2::Result.new
10
+ expect { r.count }.to raise_error(TypeError)
11
+ expect { r.fields }.to raise_error(TypeError)
12
+ expect { r.size }.to raise_error(TypeError)
13
+ expect { r.each }.to raise_error(TypeError)
11
14
  end
12
15
 
13
16
  it "should have included Enumerable" do
14
- Mysql2::Result.ancestors.include?(Enumerable).should be_true
17
+ expect(Mysql2::Result.ancestors.include?(Enumerable)).to be true
15
18
  end
16
19
 
17
20
  it "should respond to #each" do
18
- @result.should respond_to(:each)
21
+ expect(@result).to respond_to(:each)
22
+ end
23
+
24
+ it "should respond to #free" do
25
+ expect(@result).to respond_to(:free)
19
26
  end
20
27
 
21
28
  it "should raise a Mysql2::Error exception upon a bad query" do
22
- lambda {
29
+ expect do
23
30
  @client.query "bad sql"
24
- }.should raise_error(Mysql2::Error)
31
+ end.to raise_error(Mysql2::Error)
25
32
 
26
- lambda {
33
+ expect do
27
34
  @client.query "SELECT 1"
28
- }.should_not raise_error(Mysql2::Error)
35
+ end.not_to raise_error
36
+ end
37
+
38
+ it "should respond to #count, which is aliased as #size" do
39
+ r = @client.query "SELECT 1"
40
+ expect(r).to respond_to :count
41
+ expect(r).to respond_to :size
42
+ end
43
+
44
+ it "should be able to return the number of rows in the result set" do
45
+ r = @client.query "SELECT 1"
46
+ expect(r.count).to eql(1)
47
+ expect(r.size).to eql(1)
48
+ end
49
+
50
+ context "metadata queries" do
51
+ it "should show tables" do
52
+ @result = @client.query "SHOW TABLES"
53
+ end
29
54
  end
30
55
 
31
56
  context "#each" do
32
57
  it "should yield rows as hash's" do
33
58
  @result.each do |row|
34
- row.class.should eql(Hash)
59
+ expect(row).to be_an_instance_of(Hash)
35
60
  end
36
61
  end
37
62
 
38
63
  it "should yield rows as hash's with symbol keys if :symbolize_keys was set to true" do
39
- @result.each(:symbolize_keys => true) do |row|
40
- row.keys.first.class.should eql(Symbol)
64
+ @result.each(symbolize_keys: true) do |row|
65
+ expect(row.keys.first).to be_an_instance_of(Symbol)
41
66
  end
42
67
  end
43
68
 
44
69
  it "should be able to return results as an array" do
45
- @result.each(:as => :array) do |row|
46
- row.class.should eql(Array)
70
+ @result.each(as: :array) do |row|
71
+ expect(row).to be_an_instance_of(Array)
47
72
  end
48
73
  end
49
74
 
50
75
  it "should cache previously yielded results by default" do
51
- @result.first.object_id.should eql(@result.first.object_id)
76
+ expect(@result.first.object_id).to eql(@result.first.object_id)
52
77
  end
53
78
 
54
79
  it "should not cache previously yielded results if cache_rows is disabled" do
55
- result = @client.query "SELECT 1", :cache_rows => false
56
- result.first.object_id.should_not eql(result.first.object_id)
80
+ result = @client.query "SELECT 1", cache_rows: false
81
+ expect(result.first.object_id).not_to eql(result.first.object_id)
82
+ end
83
+
84
+ it "should be able to iterate a second time even if cache_rows is disabled" do
85
+ result = @client.query "SELECT 1 UNION SELECT 2", cache_rows: false
86
+ expect(result.to_a).to eql(result.to_a)
87
+ end
88
+
89
+ it "should yield different value for #first if streaming" do
90
+ result = @client.query "SELECT 1 UNION SELECT 2", stream: true, cache_rows: false
91
+ expect(result.first).not_to eql(result.first)
92
+ end
93
+
94
+ it "should yield the same value for #first if streaming is disabled" do
95
+ result = @client.query "SELECT 1 UNION SELECT 2", stream: false
96
+ expect(result.first).to eql(result.first)
97
+ end
98
+
99
+ it "should throw an exception if we try to iterate twice when streaming is enabled" do
100
+ result = @client.query "SELECT 1 UNION SELECT 2", stream: true, cache_rows: false
101
+
102
+ expect do
103
+ result.each.to_a
104
+ result.each.to_a
105
+ end.to raise_exception(Mysql2::Error)
57
106
  end
58
107
  end
59
108
 
60
109
  context "#fields" do
61
- before(:each) do
62
- @client.query "USE test"
63
- @test_result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1")
64
- end
110
+ let(:test_result) { @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1") }
65
111
 
66
112
  it "method should exist" do
67
- @test_result.should respond_to(:fields)
113
+ expect(test_result).to respond_to(:fields)
68
114
  end
69
115
 
70
116
  it "should return an array of field names in proper order" do
71
117
  result = @client.query "SELECT 'a', 'b', 'c'"
72
- result.fields.should eql(['a', 'b', 'c'])
118
+ expect(result.fields).to eql(%w[a b c])
73
119
  end
74
120
  end
75
121
 
76
- context "row data type mapping" do
77
- before(:each) do
122
+ context "streaming" do
123
+ it "should maintain a count while streaming" do
124
+ result = @client.query('SELECT 1', stream: true, cache_rows: false)
125
+ expect(result.count).to eql(0)
126
+ result.each.to_a
127
+ expect(result.count).to eql(1)
128
+ end
129
+
130
+ it "should retain the count when mixing first and each" do
131
+ result = @client.query("SELECT 1 UNION SELECT 2", stream: true, cache_rows: false)
132
+ expect(result.count).to eql(0)
133
+ result.first
134
+ expect(result.count).to eql(1)
135
+ result.each.to_a
136
+ expect(result.count).to eql(2)
137
+ end
138
+
139
+ it "should not yield nil at the end of streaming" do
140
+ result = @client.query('SELECT * FROM mysql2_test', stream: true, cache_rows: false)
141
+ result.each { |r| expect(r).not_to be_nil }
142
+ end
143
+
144
+ it "#count should be zero for rows after streaming when there were no results" do
78
145
  @client.query "USE test"
79
- @test_result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
146
+ result = @client.query("SELECT * FROM mysql2_test WHERE null_test IS NOT NULL", stream: true, cache_rows: false)
147
+ expect(result.count).to eql(0)
148
+ result.each.to_a
149
+ expect(result.count).to eql(0)
150
+ end
151
+
152
+ it "should raise an exception if streaming ended due to a timeout" do
153
+ @client.query "CREATE TEMPORARY TABLE streamingTest (val BINARY(255)) ENGINE=MEMORY"
154
+
155
+ # Insert enough records to force the result set into multiple reads
156
+ # (the BINARY type is used simply because it forces full width results)
157
+ 10000.times do |i|
158
+ @client.query "INSERT INTO streamingTest (val) VALUES ('Foo #{i}')"
159
+ end
160
+
161
+ @client.query "SET net_write_timeout = 1"
162
+ res = @client.query "SELECT * FROM streamingTest", stream: true, cache_rows: false
163
+
164
+ expect do
165
+ res.each_with_index do |_, i|
166
+ # Exhaust the first result packet then trigger a timeout
167
+ sleep 2 if i > 0 && i % 1000 == 0
168
+ end
169
+ end.to raise_error(Mysql2::Error, /Lost connection/)
170
+ end
171
+ end
172
+
173
+ context "row data type mapping" do
174
+ let(:test_result) { @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first }
175
+
176
+ it "should return nil values for NULL and strings for everything else when :cast is false" do
177
+ result = @client.query('SELECT null_test, tiny_int_test, bool_cast_test, int_test, date_test, enum_test FROM mysql2_test WHERE bool_cast_test = 1 LIMIT 1', cast: false).first
178
+ expect(result["null_test"]).to be_nil
179
+ expect(result["tiny_int_test"]).to eql("1")
180
+ expect(result["bool_cast_test"]).to eql("1")
181
+ expect(result["int_test"]).to eql("10")
182
+ expect(result["date_test"]).to eql("2010-04-04")
183
+ expect(result["enum_test"]).to eql("val1")
80
184
  end
81
185
 
82
186
  it "should return nil for a NULL value" do
83
- @test_result['null_test'].class.should eql(NilClass)
84
- @test_result['null_test'].should eql(nil)
187
+ expect(test_result['null_test']).to be_an_instance_of(NilClass)
188
+ expect(test_result['null_test']).to eql(nil)
85
189
  end
86
190
 
87
- it "should return Fixnum for a BIT value" do
88
- @test_result['bit_test'].class.should eql(String)
89
- @test_result['bit_test'].should eql("\000\000\000\000\000\000\000\005")
191
+ it "should return String for a BIT(64) value" do
192
+ expect(test_result['bit_test']).to be_an_instance_of(String)
193
+ expect(test_result['bit_test']).to eql("\000\000\000\000\000\000\000\005")
194
+ end
195
+
196
+ it "should return String for a BIT(1) value" do
197
+ expect(test_result['single_bit_test']).to be_an_instance_of(String)
198
+ expect(test_result['single_bit_test']).to eql("\001")
90
199
  end
91
200
 
92
201
  it "should return Fixnum for a TINYINT value" do
93
- [Fixnum, Bignum].should include(@test_result['tiny_int_test'].class)
94
- @test_result['tiny_int_test'].should eql(1)
202
+ expect(num_classes).to include(test_result['tiny_int_test'].class)
203
+ expect(test_result['tiny_int_test']).to eql(1)
204
+ end
205
+
206
+ context "cast booleans for TINYINT if :cast_booleans is enabled" do
207
+ # rubocop:disable Style/Semicolon
208
+ let(:id1) { @client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES ( 1)'; @client.last_id }
209
+ let(:id2) { @client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES ( 0)'; @client.last_id }
210
+ let(:id3) { @client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (-1)'; @client.last_id }
211
+ # rubocop:enable Style/Semicolon
212
+
213
+ after do
214
+ @client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2},#{id3})"
215
+ end
216
+
217
+ it "should return TrueClass or FalseClass for a TINYINT value if :cast_booleans is enabled" do
218
+ result1 = @client.query "SELECT bool_cast_test FROM mysql2_test WHERE id = #{id1} LIMIT 1", cast_booleans: true
219
+ result2 = @client.query "SELECT bool_cast_test FROM mysql2_test WHERE id = #{id2} LIMIT 1", cast_booleans: true
220
+ result3 = @client.query "SELECT bool_cast_test FROM mysql2_test WHERE id = #{id3} LIMIT 1", cast_booleans: true
221
+ expect(result1.first['bool_cast_test']).to be true
222
+ expect(result2.first['bool_cast_test']).to be false
223
+ expect(result3.first['bool_cast_test']).to be true
224
+ end
95
225
  end
96
226
 
97
- it "should return TrueClass or FalseClass for a TINYINT value if :cast_booleans is enabled" do
98
- @client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (1)'
99
- id1 = @client.last_id
100
- @client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (0)'
101
- id2 = @client.last_id
227
+ context "cast booleans for BIT(1) if :cast_booleans is enabled" do
228
+ # rubocop:disable Style/Semicolon
229
+ let(:id1) { @client.query 'INSERT INTO mysql2_test (single_bit_test) VALUES (1)'; @client.last_id }
230
+ let(:id2) { @client.query 'INSERT INTO mysql2_test (single_bit_test) VALUES (0)'; @client.last_id }
231
+ # rubocop:enable Style/Semicolon
102
232
 
103
- result1 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = 1 LIMIT 1', :cast_booleans => true
104
- result2 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = 0 LIMIT 1', :cast_booleans => true
105
- result1.first['bool_cast_test'].should be_true
106
- result2.first['bool_cast_test'].should be_false
233
+ after do
234
+ @client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2})"
235
+ end
107
236
 
108
- @client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2})"
237
+ it "should return TrueClass or FalseClass for a BIT(1) value if :cast_booleans is enabled" do
238
+ result1 = @client.query "SELECT single_bit_test FROM mysql2_test WHERE id = #{id1}", cast_booleans: true
239
+ result2 = @client.query "SELECT single_bit_test FROM mysql2_test WHERE id = #{id2}", cast_booleans: true
240
+ expect(result1.first['single_bit_test']).to be true
241
+ expect(result2.first['single_bit_test']).to be false
242
+ end
109
243
  end
110
244
 
111
245
  it "should return Fixnum for a SMALLINT value" do
112
- [Fixnum, Bignum].should include(@test_result['small_int_test'].class)
113
- @test_result['small_int_test'].should eql(10)
246
+ expect(num_classes).to include(test_result['small_int_test'].class)
247
+ expect(test_result['small_int_test']).to eql(10)
114
248
  end
115
249
 
116
250
  it "should return Fixnum for a MEDIUMINT value" do
117
- [Fixnum, Bignum].should include(@test_result['medium_int_test'].class)
118
- @test_result['medium_int_test'].should eql(10)
251
+ expect(num_classes).to include(test_result['medium_int_test'].class)
252
+ expect(test_result['medium_int_test']).to eql(10)
119
253
  end
120
254
 
121
255
  it "should return Fixnum for an INT value" do
122
- [Fixnum, Bignum].should include(@test_result['int_test'].class)
123
- @test_result['int_test'].should eql(10)
256
+ expect(num_classes).to include(test_result['int_test'].class)
257
+ expect(test_result['int_test']).to eql(10)
124
258
  end
125
259
 
126
260
  it "should return Fixnum for a BIGINT value" do
127
- [Fixnum, Bignum].should include(@test_result['big_int_test'].class)
128
- @test_result['big_int_test'].should eql(10)
261
+ expect(num_classes).to include(test_result['big_int_test'].class)
262
+ expect(test_result['big_int_test']).to eql(10)
129
263
  end
130
264
 
131
265
  it "should return Fixnum for a YEAR value" do
132
- [Fixnum, Bignum].should include(@test_result['year_test'].class)
133
- @test_result['year_test'].should eql(2009)
266
+ expect(num_classes).to include(test_result['year_test'].class)
267
+ expect(test_result['year_test']).to eql(2009)
134
268
  end
135
269
 
136
270
  it "should return BigDecimal for a DECIMAL value" do
137
- @test_result['decimal_test'].class.should eql(BigDecimal)
138
- @test_result['decimal_test'].should eql(10.3)
271
+ expect(test_result['decimal_test']).to be_an_instance_of(BigDecimal)
272
+ expect(test_result['decimal_test']).to eql(10.3)
139
273
  end
140
274
 
141
275
  it "should return Float for a FLOAT value" do
142
- @test_result['float_test'].class.should eql(Float)
143
- @test_result['float_test'].should eql(10.3)
276
+ expect(test_result['float_test']).to be_an_instance_of(Float)
277
+ expect(test_result['float_test']).to eql(10.3)
144
278
  end
145
279
 
146
280
  it "should return Float for a DOUBLE value" do
147
- @test_result['double_test'].class.should eql(Float)
148
- @test_result['double_test'].should eql(10.3)
281
+ expect(test_result['double_test']).to be_an_instance_of(Float)
282
+ expect(test_result['double_test']).to eql(10.3)
149
283
  end
150
284
 
151
285
  it "should return Time for a DATETIME value when within the supported range" do
152
- @test_result['date_time_test'].class.should eql(Time)
153
- @test_result['date_time_test'].strftime("%F %T").should eql('2010-04-04 11:44:00')
286
+ expect(test_result['date_time_test']).to be_an_instance_of(Time)
287
+ expect(test_result['date_time_test'].strftime("%Y-%m-%d %H:%M:%S")).to eql('2010-04-04 11:44:00')
154
288
  end
155
289
 
156
- it "should return DateTime for a DATETIME value when outside the supported range, Time if otherwise" do
157
- if RUBY_PLATFORM =~ /mswin/
158
- inside_year = 1970
159
- outside_year = inside_year-1
160
- else
161
- inside_year = 1902
162
- outside_year = inside_year-1
163
- end
164
- r = @client.query("SELECT CAST('#{inside_year}-1-1 01:01:01' AS DATETIME) as test")
165
- if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/
166
- klass = DateTime
167
- else
168
- klass = Time
169
- end
170
- r.first['test'].class.should eql(klass)
290
+ it "should return Time when timestamp is < 1901-12-13 20:45:52" do
291
+ r = @client.query("SELECT CAST('1901-12-13 20:45:51' AS DATETIME) as test")
292
+ expect(r.first['test']).to be_an_instance_of(Time)
293
+ end
171
294
 
172
- r = @client.query("SELECT CAST('#{outside_year}-1-1 01:01:01' AS DATETIME) as test")
173
- r.first['test'].class.should eql(DateTime)
295
+ it "should return Time when timestamp is > 2038-01-19T03:14:07" do
296
+ r = @client.query("SELECT CAST('2038-01-19 03:14:08' AS DATETIME) as test")
297
+ expect(r.first['test']).to be_an_instance_of(Time)
174
298
  end
175
299
 
176
300
  it "should return Time for a TIMESTAMP value when within the supported range" do
177
- @test_result['timestamp_test'].class.should eql(Time)
178
- @test_result['timestamp_test'].strftime("%F %T").should eql('2010-04-04 11:44:00')
301
+ expect(test_result['timestamp_test']).to be_an_instance_of(Time)
302
+ expect(test_result['timestamp_test'].strftime("%Y-%m-%d %H:%M:%S")).to eql('2010-04-04 11:44:00')
179
303
  end
180
304
 
181
305
  it "should return Time for a TIME value" do
182
- @test_result['time_test'].class.should eql(Time)
183
- @test_result['time_test'].strftime("%F %T").should eql('2000-01-01 11:44:00')
306
+ expect(test_result['time_test']).to be_an_instance_of(Time)
307
+ expect(test_result['time_test'].strftime("%Y-%m-%d %H:%M:%S")).to eql('2000-01-01 11:44:00')
184
308
  end
185
309
 
186
310
  it "should return Date for a DATE value" do
187
- @test_result['date_test'].class.should eql(Date)
188
- @test_result['date_test'].strftime("%F").should eql('2010-04-04')
311
+ expect(test_result['date_test']).to be_an_instance_of(Date)
312
+ expect(test_result['date_test'].strftime("%Y-%m-%d")).to eql('2010-04-04')
189
313
  end
190
314
 
191
315
  it "should return String for an ENUM value" do
192
- @test_result['enum_test'].class.should eql(String)
193
- @test_result['enum_test'].should eql('val1')
316
+ expect(test_result['enum_test']).to be_an_instance_of(String)
317
+ expect(test_result['enum_test']).to eql('val1')
194
318
  end
195
319
 
196
- if defined? Encoding
197
- context "string encoding for ENUM values" do
198
- it "should default to the connection's encoding if Encoding.default_internal is nil" do
199
- Encoding.default_internal = nil
320
+ it "should raise an error given an invalid DATETIME" do
321
+ expect { @client.query("SELECT CAST('1972-00-27 00:00:00' AS DATETIME) as bad_datetime").each }.to \
322
+ raise_error(Mysql2::Error, "Invalid date in field 'bad_datetime': 1972-00-27 00:00:00")
323
+ end
324
+
325
+ context "string encoding for ENUM values" do
326
+ it "should default to the connection's encoding if Encoding.default_internal is nil" do
327
+ with_internal_encoding nil do
200
328
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
201
- result['enum_test'].encoding.should eql(Encoding.find('utf-8'))
329
+ expect(result['enum_test'].encoding).to eql(Encoding::UTF_8)
202
330
 
203
- client2 = Mysql2::Client.new :encoding => 'ascii'
204
- client2.query "USE test"
331
+ client2 = new_client(encoding: 'ascii')
205
332
  result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
206
- result['enum_test'].encoding.should eql(Encoding.find('us-ascii'))
333
+ expect(result['enum_test'].encoding).to eql(Encoding::ASCII)
207
334
  end
335
+ end
208
336
 
209
- it "should use Encoding.default_internal" do
210
- Encoding.default_internal = Encoding.find('utf-8')
337
+ it "should use Encoding.default_internal" do
338
+ with_internal_encoding Encoding::UTF_8 do
211
339
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
212
- result['enum_test'].encoding.should eql(Encoding.default_internal)
213
- Encoding.default_internal = Encoding.find('us-ascii')
340
+ expect(result['enum_test'].encoding).to eql(Encoding.default_internal)
341
+ end
342
+
343
+ with_internal_encoding Encoding::ASCII do
214
344
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
215
- result['enum_test'].encoding.should eql(Encoding.default_internal)
345
+ expect(result['enum_test'].encoding).to eql(Encoding.default_internal)
216
346
  end
217
347
  end
218
348
  end
219
349
 
220
350
  it "should return String for a SET value" do
221
- @test_result['set_test'].class.should eql(String)
222
- @test_result['set_test'].should eql('val1,val2')
351
+ expect(test_result['set_test']).to be_an_instance_of(String)
352
+ expect(test_result['set_test']).to eql('val1,val2')
223
353
  end
224
354
 
225
- if defined? Encoding
226
- context "string encoding for SET values" do
227
- it "should default to the connection's encoding if Encoding.default_internal is nil" do
228
- Encoding.default_internal = nil
355
+ context "string encoding for SET values" do
356
+ it "should default to the connection's encoding if Encoding.default_internal is nil" do
357
+ with_internal_encoding nil do
229
358
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
230
- result['set_test'].encoding.should eql(Encoding.find('utf-8'))
359
+ expect(result['set_test'].encoding).to eql(Encoding::UTF_8)
231
360
 
232
- client2 = Mysql2::Client.new :encoding => 'ascii'
233
- client2.query "USE test"
361
+ client2 = new_client(encoding: 'ascii')
234
362
  result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
235
- result['set_test'].encoding.should eql(Encoding.find('us-ascii'))
363
+ expect(result['set_test'].encoding).to eql(Encoding::ASCII)
236
364
  end
365
+ end
237
366
 
238
- it "should use Encoding.default_internal" do
239
- Encoding.default_internal = Encoding.find('utf-8')
367
+ it "should use Encoding.default_internal" do
368
+ with_internal_encoding Encoding::UTF_8 do
240
369
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
241
- result['set_test'].encoding.should eql(Encoding.default_internal)
242
- Encoding.default_internal = Encoding.find('us-ascii')
370
+ expect(result['set_test'].encoding).to eql(Encoding.default_internal)
371
+ end
372
+
373
+ with_internal_encoding Encoding::ASCII do
243
374
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
244
- result['set_test'].encoding.should eql(Encoding.default_internal)
375
+ expect(result['set_test'].encoding).to eql(Encoding.default_internal)
245
376
  end
246
377
  end
247
378
  end
248
379
 
249
380
  it "should return String for a BINARY value" do
250
- @test_result['binary_test'].class.should eql(String)
251
- @test_result['binary_test'].should eql("test#{"\000"*6}")
381
+ expect(test_result['binary_test']).to be_an_instance_of(String)
382
+ expect(test_result['binary_test']).to eql("test#{"\000" * 6}")
252
383
  end
253
384
 
254
- if defined? Encoding
255
- context "string encoding for BINARY values" do
256
- it "should default to binary if Encoding.default_internal is nil" do
257
- Encoding.default_internal = nil
385
+ context "string encoding for BINARY values" do
386
+ it "should default to binary if Encoding.default_internal is nil" do
387
+ with_internal_encoding nil do
258
388
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
259
- result['binary_test'].encoding.should eql(Encoding.find('binary'))
389
+ expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
260
390
  end
391
+ end
261
392
 
262
- it "should not use Encoding.default_internal" do
263
- Encoding.default_internal = Encoding.find('utf-8')
393
+ it "should not use Encoding.default_internal" do
394
+ with_internal_encoding Encoding::UTF_8 do
264
395
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
265
- result['binary_test'].encoding.should eql(Encoding.find('binary'))
266
- Encoding.default_internal = Encoding.find('us-ascii')
396
+ expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
397
+ end
398
+
399
+ with_internal_encoding Encoding::ASCII do
267
400
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
268
- result['binary_test'].encoding.should eql(Encoding.find('binary'))
401
+ expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
269
402
  end
270
403
  end
271
404
  end
@@ -281,53 +414,72 @@ describe Mysql2::Result do
281
414
  'medium_blob_test' => 'MEDIUMBLOB',
282
415
  'medium_text_test' => 'MEDIUMTEXT',
283
416
  'long_blob_test' => 'LONGBLOB',
284
- 'long_text_test' => 'LONGTEXT'
417
+ 'long_text_test' => 'LONGTEXT',
285
418
  }.each do |field, type|
286
419
  it "should return a String for #{type}" do
287
- @test_result[field].class.should eql(String)
288
- @test_result[field].should eql("test")
420
+ expect(test_result[field]).to be_an_instance_of(String)
421
+ expect(test_result[field]).to eql("test")
289
422
  end
290
423
 
291
- if defined? Encoding
292
- context "string encoding for #{type} values" do
293
- if ['VARBINARY', 'TINYBLOB', 'BLOB', 'MEDIUMBLOB', 'LONGBLOB'].include?(type)
294
- it "should default to binary if Encoding.default_internal is nil" do
295
- Encoding.default_internal = nil
424
+ context "string encoding for #{type} values" do
425
+ if %w[VARBINARY TINYBLOB BLOB MEDIUMBLOB LONGBLOB].include?(type)
426
+ it "should default to binary if Encoding.default_internal is nil" do
427
+ with_internal_encoding nil do
296
428
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
297
- result['binary_test'].encoding.should eql(Encoding.find('binary'))
429
+ expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
298
430
  end
431
+ end
299
432
 
300
- it "should not use Encoding.default_internal" do
301
- Encoding.default_internal = Encoding.find('utf-8')
433
+ it "should not use Encoding.default_internal" do
434
+ with_internal_encoding Encoding::UTF_8 do
302
435
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
303
- result['binary_test'].encoding.should eql(Encoding.find('binary'))
304
- Encoding.default_internal = Encoding.find('us-ascii')
436
+ expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
437
+ end
438
+
439
+ with_internal_encoding Encoding::ASCII do
305
440
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
306
- result['binary_test'].encoding.should eql(Encoding.find('binary'))
441
+ expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
307
442
  end
308
- else
309
- it "should default to utf-8 if Encoding.default_internal is nil" do
310
- Encoding.default_internal = nil
443
+ end
444
+ else
445
+ it "should default to utf-8 if Encoding.default_internal is nil" do
446
+ with_internal_encoding nil do
311
447
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
312
- result[field].encoding.should eql(Encoding.find('utf-8'))
448
+ expect(result[field].encoding).to eql(Encoding::UTF_8)
313
449
 
314
- client2 = Mysql2::Client.new :encoding => 'ascii'
315
- client2.query "USE test"
450
+ client2 = new_client(encoding: 'ascii')
316
451
  result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
317
- result[field].encoding.should eql(Encoding.find('us-ascii'))
452
+ expect(result[field].encoding).to eql(Encoding::ASCII)
318
453
  end
454
+ end
319
455
 
320
- it "should use Encoding.default_internal" do
321
- Encoding.default_internal = Encoding.find('utf-8')
456
+ it "should use Encoding.default_internal" do
457
+ with_internal_encoding Encoding::UTF_8 do
322
458
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
323
- result[field].encoding.should eql(Encoding.default_internal)
324
- Encoding.default_internal = Encoding.find('us-ascii')
459
+ expect(result[field].encoding).to eql(Encoding.default_internal)
460
+ end
461
+
462
+ with_internal_encoding Encoding::ASCII do
325
463
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
326
- result[field].encoding.should eql(Encoding.default_internal)
464
+ expect(result[field].encoding).to eql(Encoding.default_internal)
327
465
  end
328
466
  end
329
467
  end
330
468
  end
331
469
  end
332
470
  end
471
+
472
+ context "server flags" do
473
+ let(:test_result) { @client.query("SELECT * FROM mysql2_test ORDER BY null_test DESC LIMIT 1") }
474
+
475
+ it "should set a definitive value for query_was_slow" do
476
+ expect(test_result.server_flags[:query_was_slow]).to eql(false)
477
+ end
478
+ it "should set a definitive value for no_index_used" do
479
+ expect(test_result.server_flags[:no_index_used]).to eql(true)
480
+ end
481
+ it "should set a definitive value for no_good_index_used" do
482
+ expect(test_result.server_flags[:no_good_index_used]).to eql(false)
483
+ end
484
+ end
333
485
  end