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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1 -151
- data/LICENSE +21 -0
- data/README.md +634 -0
- data/examples/eventmachine.rb +1 -3
- data/examples/threaded.rb +5 -9
- data/ext/mysql2/client.c +1154 -342
- data/ext/mysql2/client.h +20 -33
- data/ext/mysql2/extconf.rb +229 -37
- data/ext/mysql2/infile.c +122 -0
- data/ext/mysql2/infile.h +1 -0
- data/ext/mysql2/mysql2_ext.c +3 -1
- data/ext/mysql2/mysql2_ext.h +18 -16
- data/ext/mysql2/mysql_enc_name_to_ruby.h +168 -0
- data/ext/mysql2/mysql_enc_to_ruby.h +259 -0
- data/ext/mysql2/result.c +708 -191
- data/ext/mysql2/result.h +15 -6
- data/ext/mysql2/statement.c +602 -0
- data/ext/mysql2/statement.h +17 -0
- data/ext/mysql2/wait_for_single_fd.h +37 -0
- data/lib/mysql2.rb +69 -7
- data/lib/mysql2/client.rb +126 -211
- data/lib/mysql2/console.rb +5 -0
- data/lib/mysql2/em.rb +24 -8
- data/lib/mysql2/error.rb +93 -8
- data/lib/mysql2/field.rb +3 -0
- data/lib/mysql2/result.rb +2 -0
- data/lib/mysql2/statement.rb +11 -0
- data/lib/mysql2/version.rb +2 -2
- data/spec/configuration.yml.example +11 -0
- data/spec/em/em_spec.rb +101 -15
- data/spec/my.cnf.example +9 -0
- data/spec/mysql2/client_spec.rb +874 -232
- data/spec/mysql2/error_spec.rb +55 -46
- data/spec/mysql2/result_spec.rb +306 -154
- data/spec/mysql2/statement_spec.rb +712 -0
- data/spec/spec_helper.rb +103 -57
- data/spec/ssl/ca-cert.pem +17 -0
- data/spec/ssl/ca-key.pem +27 -0
- data/spec/ssl/ca.cnf +22 -0
- data/spec/ssl/cert.cnf +22 -0
- data/spec/ssl/client-cert.pem +17 -0
- data/spec/ssl/client-key.pem +27 -0
- data/spec/ssl/client-req.pem +15 -0
- data/spec/ssl/gen_certs.sh +48 -0
- data/spec/ssl/pkcs8-client-key.pem +28 -0
- data/spec/ssl/pkcs8-server-key.pem +28 -0
- data/spec/ssl/server-cert.pem +17 -0
- data/spec/ssl/server-key.pem +27 -0
- data/spec/ssl/server-req.pem +15 -0
- data/spec/test_data +1 -0
- data/support/5072E1F5.asc +432 -0
- data/support/libmysql.def +219 -0
- data/support/mysql_enc_to_ruby.rb +81 -0
- data/support/ruby_enc_to_mysql.rb +61 -0
- metadata +82 -188
- data/.gitignore +0 -12
- data/.rspec +0 -2
- data/.rvmrc +0 -1
- data/Gemfile +0 -3
- data/MIT-LICENSE +0 -20
- data/README.rdoc +0 -257
- data/Rakefile +0 -5
- data/benchmark/active_record.rb +0 -51
- data/benchmark/active_record_threaded.rb +0 -42
- data/benchmark/allocations.rb +0 -33
- data/benchmark/escape.rb +0 -36
- data/benchmark/query_with_mysql_casting.rb +0 -80
- data/benchmark/query_without_mysql_casting.rb +0 -47
- data/benchmark/sequel.rb +0 -37
- data/benchmark/setup_db.rb +0 -119
- data/benchmark/threaded.rb +0 -44
- data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +0 -64
- data/lib/active_record/fiber_patches.rb +0 -104
- data/lib/mysql2/em_fiber.rb +0 -31
- data/mysql2.gemspec +0 -32
- data/spec/em/em_fiber_spec.rb +0 -22
- data/tasks/benchmarks.rake +0 -20
- data/tasks/compile.rake +0 -71
- data/tasks/rspec.rake +0 -16
- data/tasks/vendor_mysql.rake +0 -40
data/spec/mysql2/error_spec.rb
CHANGED
@@ -1,68 +1,77 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
require 'spec_helper'
|
3
2
|
|
4
|
-
describe Mysql2::Error do
|
5
|
-
|
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
|
-
|
8
|
+
error = e
|
11
9
|
end
|
12
10
|
|
13
|
-
|
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 "
|
22
|
-
|
23
|
-
|
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
|
-
|
26
|
-
|
18
|
+
# Mysql gem compatibility
|
19
|
+
expect(error).to respond_to(:errno)
|
20
|
+
expect(error).to respond_to(:error)
|
27
21
|
end
|
28
22
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
41
|
-
@
|
42
|
-
|
43
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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 "
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
data/spec/mysql2/result_spec.rb
CHANGED
@@ -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
|
-
@
|
5
|
+
@result = @client.query "SELECT 1"
|
7
6
|
end
|
8
7
|
|
9
|
-
|
10
|
-
|
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).
|
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.
|
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
|
-
|
29
|
+
expect do
|
23
30
|
@client.query "bad sql"
|
24
|
-
|
31
|
+
end.to raise_error(Mysql2::Error)
|
25
32
|
|
26
|
-
|
33
|
+
expect do
|
27
34
|
@client.query "SELECT 1"
|
28
|
-
|
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.
|
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(:
|
40
|
-
row.keys.first.
|
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(:
|
46
|
-
row.
|
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.
|
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", :
|
56
|
-
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
|
-
|
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
|
-
|
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.
|
118
|
+
expect(result.fields).to eql(%w[a b c])
|
73
119
|
end
|
74
120
|
end
|
75
121
|
|
76
|
-
context "
|
77
|
-
|
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
|
-
|
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
|
-
|
84
|
-
|
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
|
88
|
-
|
89
|
-
|
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
|
-
|
94
|
-
|
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
|
-
|
98
|
-
|
99
|
-
id1
|
100
|
-
@client.query 'INSERT INTO mysql2_test (
|
101
|
-
|
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
|
-
|
104
|
-
|
105
|
-
|
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
|
-
|
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
|
-
|
113
|
-
|
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
|
-
|
118
|
-
|
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
|
-
|
123
|
-
|
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
|
-
|
128
|
-
|
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
|
-
|
133
|
-
|
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
|
-
|
138
|
-
|
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
|
-
|
143
|
-
|
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
|
-
|
148
|
-
|
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
|
-
|
153
|
-
|
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
|
157
|
-
|
158
|
-
|
159
|
-
|
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
|
-
|
173
|
-
r.
|
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
|
-
|
178
|
-
|
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
|
-
|
183
|
-
|
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
|
-
|
188
|
-
|
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
|
-
|
193
|
-
|
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
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
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.
|
329
|
+
expect(result['enum_test'].encoding).to eql(Encoding::UTF_8)
|
202
330
|
|
203
|
-
client2 =
|
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.
|
333
|
+
expect(result['enum_test'].encoding).to eql(Encoding::ASCII)
|
207
334
|
end
|
335
|
+
end
|
208
336
|
|
209
|
-
|
210
|
-
|
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.
|
213
|
-
|
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.
|
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
|
-
|
222
|
-
|
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
|
-
|
226
|
-
|
227
|
-
|
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.
|
359
|
+
expect(result['set_test'].encoding).to eql(Encoding::UTF_8)
|
231
360
|
|
232
|
-
client2 =
|
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.
|
363
|
+
expect(result['set_test'].encoding).to eql(Encoding::ASCII)
|
236
364
|
end
|
365
|
+
end
|
237
366
|
|
238
|
-
|
239
|
-
|
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.
|
242
|
-
|
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.
|
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
|
-
|
251
|
-
|
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
|
-
|
255
|
-
|
256
|
-
|
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.
|
389
|
+
expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
|
260
390
|
end
|
391
|
+
end
|
261
392
|
|
262
|
-
|
263
|
-
|
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.
|
266
|
-
|
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.
|
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
|
-
|
288
|
-
|
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
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
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.
|
429
|
+
expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
|
298
430
|
end
|
431
|
+
end
|
299
432
|
|
300
|
-
|
301
|
-
|
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.
|
304
|
-
|
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.
|
441
|
+
expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
|
307
442
|
end
|
308
|
-
|
309
|
-
|
310
|
-
|
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.
|
448
|
+
expect(result[field].encoding).to eql(Encoding::UTF_8)
|
313
449
|
|
314
|
-
client2 =
|
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.
|
452
|
+
expect(result[field].encoding).to eql(Encoding::ASCII)
|
318
453
|
end
|
454
|
+
end
|
319
455
|
|
320
|
-
|
321
|
-
|
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.
|
324
|
-
|
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.
|
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
|