mysql2 0.4.10 → 0.5.4
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 +5 -5
- data/README.md +98 -38
- data/ext/mysql2/client.c +223 -76
- data/ext/mysql2/client.h +1 -39
- data/ext/mysql2/extconf.rb +46 -26
- data/ext/mysql2/mysql2_ext.c +8 -2
- data/ext/mysql2/mysql2_ext.h +8 -4
- data/ext/mysql2/mysql_enc_name_to_ruby.h +60 -56
- data/ext/mysql2/mysql_enc_to_ruby.h +64 -3
- data/ext/mysql2/result.c +242 -86
- data/ext/mysql2/result.h +3 -3
- data/ext/mysql2/statement.c +90 -73
- data/ext/mysql2/statement.h +0 -2
- data/ext/mysql2/wait_for_single_fd.h +2 -1
- data/lib/mysql2/client.rb +51 -28
- data/lib/mysql2/em.rb +2 -4
- data/lib/mysql2/error.rb +52 -22
- data/lib/mysql2/result.rb +2 -0
- data/lib/mysql2/statement.rb +3 -11
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +18 -15
- data/support/3A79BD29.asc +49 -0
- data/support/5072E1F5.asc +5 -5
- data/support/mysql_enc_to_ruby.rb +8 -3
- data/support/ruby_enc_to_mysql.rb +7 -5
- metadata +14 -58
- data/examples/eventmachine.rb +0 -21
- data/examples/threaded.rb +0 -18
- data/spec/configuration.yml.example +0 -11
- data/spec/em/em_spec.rb +0 -136
- data/spec/my.cnf.example +0 -9
- data/spec/mysql2/client_spec.rb +0 -1039
- data/spec/mysql2/error_spec.rb +0 -82
- data/spec/mysql2/result_spec.rb +0 -545
- data/spec/mysql2/statement_spec.rb +0 -776
- data/spec/rcov.opts +0 -3
- data/spec/spec_helper.rb +0 -108
- data/spec/ssl/ca-cert.pem +0 -17
- data/spec/ssl/ca-key.pem +0 -27
- data/spec/ssl/ca.cnf +0 -22
- data/spec/ssl/cert.cnf +0 -22
- data/spec/ssl/client-cert.pem +0 -17
- data/spec/ssl/client-key.pem +0 -27
- data/spec/ssl/client-req.pem +0 -15
- data/spec/ssl/gen_certs.sh +0 -48
- data/spec/ssl/pkcs8-client-key.pem +0 -28
- data/spec/ssl/pkcs8-server-key.pem +0 -28
- data/spec/ssl/server-cert.pem +0 -17
- data/spec/ssl/server-key.pem +0 -27
- data/spec/ssl/server-req.pem +0 -15
- data/spec/test_data +0 -1
@@ -1,776 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
require './spec/spec_helper.rb'
|
3
|
-
|
4
|
-
RSpec.describe Mysql2::Statement do
|
5
|
-
before :each do
|
6
|
-
@client = new_client(:encoding => "utf8")
|
7
|
-
end
|
8
|
-
|
9
|
-
def stmt_count
|
10
|
-
@client.query("SHOW STATUS LIKE 'Prepared_stmt_count'").first['Value'].to_i
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should create a statement" do
|
14
|
-
statement = nil
|
15
|
-
expect { statement = @client.prepare 'SELECT 1' }.to change(&method(:stmt_count)).by(1)
|
16
|
-
expect(statement).to be_an_instance_of(Mysql2::Statement)
|
17
|
-
end
|
18
|
-
|
19
|
-
it "should raise an exception when server disconnects" do
|
20
|
-
@client.close
|
21
|
-
expect { @client.prepare 'SELECT 1' }.to raise_error(Mysql2::Error)
|
22
|
-
end
|
23
|
-
|
24
|
-
it "should tell us the param count" do
|
25
|
-
statement = @client.prepare 'SELECT ?, ?'
|
26
|
-
expect(statement.param_count).to eq(2)
|
27
|
-
|
28
|
-
statement2 = @client.prepare 'SELECT 1'
|
29
|
-
expect(statement2.param_count).to eq(0)
|
30
|
-
end
|
31
|
-
|
32
|
-
it "should tell us the field count" do
|
33
|
-
statement = @client.prepare 'SELECT ?, ?'
|
34
|
-
expect(statement.field_count).to eq(2)
|
35
|
-
|
36
|
-
statement2 = @client.prepare 'SELECT 1'
|
37
|
-
expect(statement2.field_count).to eq(1)
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should let us execute our statement" do
|
41
|
-
statement = @client.prepare 'SELECT 1'
|
42
|
-
expect(statement.execute).not_to eq(nil)
|
43
|
-
end
|
44
|
-
|
45
|
-
it "should raise an exception without a block" do
|
46
|
-
statement = @client.prepare 'SELECT 1'
|
47
|
-
expect { statement.execute.each }.to raise_error(LocalJumpError)
|
48
|
-
end
|
49
|
-
|
50
|
-
it "should tell us the result count" do
|
51
|
-
statement = @client.prepare 'SELECT 1'
|
52
|
-
result = statement.execute
|
53
|
-
expect(result.count).to eq(1)
|
54
|
-
end
|
55
|
-
|
56
|
-
it "should let us iterate over results" do
|
57
|
-
statement = @client.prepare 'SELECT 1'
|
58
|
-
result = statement.execute
|
59
|
-
rows = []
|
60
|
-
result.each { |r| rows << r }
|
61
|
-
expect(rows).to eq([{ "1" => 1 }])
|
62
|
-
end
|
63
|
-
|
64
|
-
it "should handle booleans" do
|
65
|
-
stmt = @client.prepare('SELECT ? AS `true`, ? AS `false`')
|
66
|
-
result = stmt.execute(true, false)
|
67
|
-
expect(result.to_a).to eq(['true' => 1, 'false' => 0])
|
68
|
-
end
|
69
|
-
|
70
|
-
it "should handle bignum but in int64_t" do
|
71
|
-
stmt = @client.prepare('SELECT ? AS max, ? AS min')
|
72
|
-
int64_max = (1 << 63) - 1
|
73
|
-
int64_min = -(1 << 63)
|
74
|
-
result = stmt.execute(int64_max, int64_min)
|
75
|
-
expect(result.to_a).to eq(['max' => int64_max, 'min' => int64_min])
|
76
|
-
end
|
77
|
-
|
78
|
-
it "should handle bignum but beyond int64_t" do
|
79
|
-
stmt = @client.prepare('SELECT ? AS max1, ? AS max2, ? AS max3, ? AS min1, ? AS min2, ? AS min3')
|
80
|
-
int64_max1 = (1 << 63)
|
81
|
-
int64_max2 = (1 << 64) - 1
|
82
|
-
int64_max3 = 1 << 64
|
83
|
-
int64_min1 = -(1 << 63) - 1
|
84
|
-
int64_min2 = -(1 << 64) + 1
|
85
|
-
int64_min3 = -0xC000000000000000
|
86
|
-
result = stmt.execute(int64_max1, int64_max2, int64_max3, int64_min1, int64_min2, int64_min3)
|
87
|
-
expect(result.to_a).to eq(['max1' => int64_max1, 'max2' => int64_max2, 'max3' => int64_max3, 'min1' => int64_min1, 'min2' => int64_min2, 'min3' => int64_min3])
|
88
|
-
end
|
89
|
-
|
90
|
-
it "should keep its result after other query" do
|
91
|
-
@client.query 'USE test'
|
92
|
-
@client.query 'CREATE TABLE IF NOT EXISTS mysql2_stmt_q(a int)'
|
93
|
-
@client.query 'INSERT INTO mysql2_stmt_q (a) VALUES (1), (2)'
|
94
|
-
stmt = @client.prepare('SELECT a FROM mysql2_stmt_q WHERE a = ?')
|
95
|
-
result1 = stmt.execute(1)
|
96
|
-
result2 = stmt.execute(2)
|
97
|
-
expect(result2.first).to eq("a" => 2)
|
98
|
-
expect(result1.first).to eq("a" => 1)
|
99
|
-
@client.query 'DROP TABLE IF EXISTS mysql2_stmt_q'
|
100
|
-
end
|
101
|
-
|
102
|
-
it "should be reusable 1000 times" do
|
103
|
-
statement = @client.prepare 'SELECT 1'
|
104
|
-
1000.times do
|
105
|
-
result = statement.execute
|
106
|
-
expect(result.to_a.length).to eq(1)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
it "should be reusable 10000 times" do
|
111
|
-
statement = @client.prepare 'SELECT 1'
|
112
|
-
10000.times do
|
113
|
-
result = statement.execute
|
114
|
-
expect(result.to_a.length).to eq(1)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
it "should handle comparisons and likes" do
|
119
|
-
@client.query 'USE test'
|
120
|
-
@client.query 'CREATE TABLE IF NOT EXISTS mysql2_stmt_q(a int, b varchar(10))'
|
121
|
-
@client.query 'INSERT INTO mysql2_stmt_q (a, b) VALUES (1, "Hello"), (2, "World")'
|
122
|
-
statement = @client.prepare 'SELECT * FROM mysql2_stmt_q WHERE a < ?'
|
123
|
-
results = statement.execute(2)
|
124
|
-
expect(results.first).to eq("a" => 1, "b" => "Hello")
|
125
|
-
|
126
|
-
statement = @client.prepare 'SELECT * FROM mysql2_stmt_q WHERE b LIKE ?'
|
127
|
-
results = statement.execute('%orld')
|
128
|
-
expect(results.first).to eq("a" => 2, "b" => "World")
|
129
|
-
|
130
|
-
@client.query 'DROP TABLE IF EXISTS mysql2_stmt_q'
|
131
|
-
end
|
132
|
-
|
133
|
-
it "should select dates" do
|
134
|
-
statement = @client.prepare 'SELECT NOW()'
|
135
|
-
result = statement.execute
|
136
|
-
expect(result.first.first[1]).to be_an_instance_of(Time)
|
137
|
-
end
|
138
|
-
|
139
|
-
it "should prepare Date values" do
|
140
|
-
now = Date.today
|
141
|
-
statement = @client.prepare('SELECT ? AS a')
|
142
|
-
result = statement.execute(now)
|
143
|
-
expect(result.first['a'].to_s).to eql(now.strftime('%F'))
|
144
|
-
end
|
145
|
-
|
146
|
-
it "should prepare Time values with microseconds" do
|
147
|
-
now = Time.now
|
148
|
-
statement = @client.prepare('SELECT ? AS a')
|
149
|
-
result = statement.execute(now)
|
150
|
-
if RUBY_VERSION =~ /1.8/
|
151
|
-
expect(result.first['a'].strftime('%F %T %z')).to eql(now.strftime('%F %T %z'))
|
152
|
-
else
|
153
|
-
# microseconds is six digits after the decimal, but only test on 5 significant figures
|
154
|
-
expect(result.first['a'].strftime('%F %T.%5N %z')).to eql(now.strftime('%F %T.%5N %z'))
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
it "should prepare DateTime values with microseconds" do
|
159
|
-
now = DateTime.now
|
160
|
-
statement = @client.prepare('SELECT ? AS a')
|
161
|
-
result = statement.execute(now)
|
162
|
-
if RUBY_VERSION =~ /1.8/
|
163
|
-
expect(result.first['a'].strftime('%F %T %z')).to eql(now.strftime('%F %T %z'))
|
164
|
-
else
|
165
|
-
# microseconds is six digits after the decimal, but only test on 5 significant figures
|
166
|
-
expect(result.first['a'].strftime('%F %T.%5N %z')).to eql(now.strftime('%F %T.%5N %z'))
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
it "should tell us about the fields" do
|
171
|
-
statement = @client.prepare 'SELECT 1 as foo, 2'
|
172
|
-
statement.execute
|
173
|
-
list = statement.fields
|
174
|
-
expect(list.length).to eq(2)
|
175
|
-
expect(list.first).to eq('foo')
|
176
|
-
expect(list[1]).to eq('2')
|
177
|
-
end
|
178
|
-
|
179
|
-
it "should handle as a decimal binding a BigDecimal" do
|
180
|
-
stmt = @client.prepare('SELECT ? AS decimal_test')
|
181
|
-
test_result = stmt.execute(BigDecimal.new("123.45")).first
|
182
|
-
expect(test_result['decimal_test']).to be_an_instance_of(BigDecimal)
|
183
|
-
expect(test_result['decimal_test']).to eql(123.45)
|
184
|
-
end
|
185
|
-
|
186
|
-
it "should update a DECIMAL value passing a BigDecimal" do
|
187
|
-
@client.query 'USE test'
|
188
|
-
@client.query 'DROP TABLE IF EXISTS mysql2_stmt_decimal_test'
|
189
|
-
@client.query 'CREATE TABLE mysql2_stmt_decimal_test (decimal_test DECIMAL(10,3))'
|
190
|
-
|
191
|
-
@client.prepare("INSERT INTO mysql2_stmt_decimal_test VALUES (?)").execute(BigDecimal.new("123.45"))
|
192
|
-
|
193
|
-
test_result = @client.query("SELECT * FROM mysql2_stmt_decimal_test").first
|
194
|
-
expect(test_result['decimal_test']).to eql(123.45)
|
195
|
-
end
|
196
|
-
|
197
|
-
it "should warn but still work if cache_rows is set to false" do
|
198
|
-
@client.query_options.merge!(:cache_rows => false)
|
199
|
-
statement = @client.prepare 'SELECT 1'
|
200
|
-
result = nil
|
201
|
-
expect { result = statement.execute.to_a }.to output(/:cache_rows is forced for prepared statements/).to_stderr
|
202
|
-
expect(result.length).to eq(1)
|
203
|
-
end
|
204
|
-
|
205
|
-
context "utf8_db" do
|
206
|
-
before(:each) do
|
207
|
-
@client.query("DROP DATABASE IF EXISTS test_mysql2_stmt_utf8")
|
208
|
-
@client.query("CREATE DATABASE test_mysql2_stmt_utf8")
|
209
|
-
@client.query("USE test_mysql2_stmt_utf8")
|
210
|
-
@client.query("CREATE TABLE テーブル (整数 int, 文字列 varchar(32)) charset=utf8")
|
211
|
-
@client.query("INSERT INTO テーブル (整数, 文字列) VALUES (1, 'イチ'), (2, '弐'), (3, 'さん')")
|
212
|
-
end
|
213
|
-
|
214
|
-
after(:each) do
|
215
|
-
@client.query("DROP DATABASE test_mysql2_stmt_utf8")
|
216
|
-
end
|
217
|
-
|
218
|
-
it "should be able to retrieve utf8 field names correctly" do
|
219
|
-
stmt = @client.prepare 'SELECT * FROM `テーブル`'
|
220
|
-
expect(stmt.fields).to eq(%w(整数 文字列))
|
221
|
-
result = stmt.execute
|
222
|
-
|
223
|
-
expect(result.to_a).to eq([{ "整数" => 1, "文字列" => "イチ" }, { "整数" => 2, "文字列" => "弐" }, { "整数" => 3, "文字列" => "さん" }])
|
224
|
-
end
|
225
|
-
|
226
|
-
it "should be able to retrieve utf8 param query correctly" do
|
227
|
-
stmt = @client.prepare 'SELECT 整数 FROM テーブル WHERE 文字列 = ?'
|
228
|
-
expect(stmt.param_count).to eq(1)
|
229
|
-
|
230
|
-
result = stmt.execute 'イチ'
|
231
|
-
|
232
|
-
expect(result.to_a).to eq([{ "整数" => 1 }])
|
233
|
-
end
|
234
|
-
|
235
|
-
it "should be able to retrieve query with param in different encoding correctly" do
|
236
|
-
stmt = @client.prepare 'SELECT 整数 FROM テーブル WHERE 文字列 = ?'
|
237
|
-
expect(stmt.param_count).to eq(1)
|
238
|
-
|
239
|
-
param = 'イチ'.encode("EUC-JP")
|
240
|
-
result = stmt.execute param
|
241
|
-
|
242
|
-
expect(result.to_a).to eq([{ "整数" => 1 }])
|
243
|
-
end
|
244
|
-
end if defined? Encoding
|
245
|
-
|
246
|
-
context "streaming result" do
|
247
|
-
it "should be able to stream query result" do
|
248
|
-
n = 1
|
249
|
-
stmt = @client.prepare("SELECT 1 UNION SELECT 2")
|
250
|
-
|
251
|
-
@client.query_options.merge!(:stream => true, :cache_rows => false, :as => :array)
|
252
|
-
|
253
|
-
stmt.execute.each do |r|
|
254
|
-
case n
|
255
|
-
when 1
|
256
|
-
expect(r).to eq([1])
|
257
|
-
when 2
|
258
|
-
expect(r).to eq([2])
|
259
|
-
else
|
260
|
-
violated "returned more than two rows"
|
261
|
-
end
|
262
|
-
n += 1
|
263
|
-
end
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
context "#each" do
|
268
|
-
# note: The current impl. of prepared statement requires results to be cached on #execute except for streaming queries
|
269
|
-
# The drawback of this is that args of Result#each is ignored...
|
270
|
-
|
271
|
-
it "should yield rows as hash's" do
|
272
|
-
@result = @client.prepare("SELECT 1").execute
|
273
|
-
@result.each do |row|
|
274
|
-
expect(row).to be_an_instance_of(Hash)
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
it "should yield rows as hash's with symbol keys if :symbolize_keys was set to true" do
|
279
|
-
@client.query_options[:symbolize_keys] = true
|
280
|
-
@result = @client.prepare("SELECT 1").execute
|
281
|
-
@result.each do |row|
|
282
|
-
expect(row.keys.first).to be_an_instance_of(Symbol)
|
283
|
-
end
|
284
|
-
@client.query_options[:symbolize_keys] = false
|
285
|
-
end
|
286
|
-
|
287
|
-
it "should be able to return results as an array" do
|
288
|
-
@client.query_options[:as] = :array
|
289
|
-
|
290
|
-
@result = @client.prepare("SELECT 1").execute
|
291
|
-
@result.each do |row|
|
292
|
-
expect(row).to be_an_instance_of(Array)
|
293
|
-
end
|
294
|
-
|
295
|
-
@client.query_options[:as] = :hash
|
296
|
-
end
|
297
|
-
|
298
|
-
it "should cache previously yielded results by default" do
|
299
|
-
@result = @client.prepare("SELECT 1").execute
|
300
|
-
expect(@result.first.object_id).to eql(@result.first.object_id)
|
301
|
-
end
|
302
|
-
|
303
|
-
it "should yield different value for #first if streaming" do
|
304
|
-
@client.query_options[:stream] = true
|
305
|
-
@client.query_options[:cache_rows] = false
|
306
|
-
|
307
|
-
result = @client.prepare("SELECT 1 UNION SELECT 2").execute
|
308
|
-
expect(result.first).not_to eql(result.first)
|
309
|
-
|
310
|
-
@client.query_options[:stream] = false
|
311
|
-
@client.query_options[:cache_rows] = true
|
312
|
-
end
|
313
|
-
|
314
|
-
it "should yield the same value for #first if streaming is disabled" do
|
315
|
-
@client.query_options[:stream] = false
|
316
|
-
result = @client.prepare("SELECT 1 UNION SELECT 2").execute
|
317
|
-
expect(result.first).to eql(result.first)
|
318
|
-
end
|
319
|
-
|
320
|
-
it "should throw an exception if we try to iterate twice when streaming is enabled" do
|
321
|
-
@client.query_options[:stream] = true
|
322
|
-
@client.query_options[:cache_rows] = false
|
323
|
-
|
324
|
-
result = @client.prepare("SELECT 1 UNION SELECT 2").execute
|
325
|
-
|
326
|
-
expect {
|
327
|
-
result.each {}
|
328
|
-
result.each {}
|
329
|
-
}.to raise_exception(Mysql2::Error)
|
330
|
-
|
331
|
-
@client.query_options[:stream] = false
|
332
|
-
@client.query_options[:cache_rows] = true
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
context "#fields" do
|
337
|
-
it "method should exist" do
|
338
|
-
stmt = @client.prepare("SELECT 1")
|
339
|
-
expect(stmt).to respond_to(:fields)
|
340
|
-
end
|
341
|
-
|
342
|
-
it "should return an array of field names in proper order" do
|
343
|
-
stmt = @client.prepare("SELECT 'a', 'b', 'c'")
|
344
|
-
expect(stmt.fields).to eql(%w(a b c))
|
345
|
-
end
|
346
|
-
|
347
|
-
it "should return nil for statement with no result fields" do
|
348
|
-
stmt = @client.prepare("INSERT INTO mysql2_test () VALUES ()")
|
349
|
-
expect(stmt.fields).to eql(nil)
|
350
|
-
end
|
351
|
-
end
|
352
|
-
|
353
|
-
context "row data type mapping" do
|
354
|
-
before(:each) do
|
355
|
-
@client.query "USE test"
|
356
|
-
@test_result = @client.prepare("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").execute.first
|
357
|
-
end
|
358
|
-
|
359
|
-
it "should return nil for a NULL value" do
|
360
|
-
expect(@test_result['null_test']).to be_an_instance_of(NilClass)
|
361
|
-
expect(@test_result['null_test']).to eql(nil)
|
362
|
-
end
|
363
|
-
|
364
|
-
it "should return String for a BIT(64) value" do
|
365
|
-
expect(@test_result['bit_test']).to be_an_instance_of(String)
|
366
|
-
expect(@test_result['bit_test']).to eql("\000\000\000\000\000\000\000\005")
|
367
|
-
end
|
368
|
-
|
369
|
-
it "should return String for a BIT(1) value" do
|
370
|
-
expect(@test_result['single_bit_test']).to be_an_instance_of(String)
|
371
|
-
expect(@test_result['single_bit_test']).to eql("\001")
|
372
|
-
end
|
373
|
-
|
374
|
-
it "should return Fixnum for a TINYINT value" do
|
375
|
-
expect([Fixnum, Bignum]).to include(@test_result['tiny_int_test'].class)
|
376
|
-
expect(@test_result['tiny_int_test']).to eql(1)
|
377
|
-
end
|
378
|
-
|
379
|
-
context "cast booleans for TINYINT if :cast_booleans is enabled" do
|
380
|
-
# rubocop:disable Style/Semicolon
|
381
|
-
let(:client) { new_client(:cast_booleans => true) }
|
382
|
-
let(:id1) { client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES ( 1)'; client.last_id }
|
383
|
-
let(:id2) { client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES ( 0)'; client.last_id }
|
384
|
-
let(:id3) { client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (-1)'; client.last_id }
|
385
|
-
# rubocop:enable Style/Semicolon
|
386
|
-
|
387
|
-
after do
|
388
|
-
client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2},#{id3})"
|
389
|
-
end
|
390
|
-
|
391
|
-
it "should return TrueClass or FalseClass for a TINYINT value if :cast_booleans is enabled" do
|
392
|
-
query = client.prepare 'SELECT bool_cast_test FROM mysql2_test WHERE id = ?'
|
393
|
-
result1 = query.execute id1
|
394
|
-
result2 = query.execute id2
|
395
|
-
result3 = query.execute id3
|
396
|
-
expect(result1.first['bool_cast_test']).to be true
|
397
|
-
expect(result2.first['bool_cast_test']).to be false
|
398
|
-
expect(result3.first['bool_cast_test']).to be true
|
399
|
-
end
|
400
|
-
end
|
401
|
-
|
402
|
-
context "cast booleans for BIT(1) if :cast_booleans is enabled" do
|
403
|
-
# rubocop:disable Style/Semicolon
|
404
|
-
let(:client) { new_client(:cast_booleans => true) }
|
405
|
-
let(:id1) { client.query 'INSERT INTO mysql2_test (single_bit_test) VALUES (1)'; client.last_id }
|
406
|
-
let(:id2) { client.query 'INSERT INTO mysql2_test (single_bit_test) VALUES (0)'; client.last_id }
|
407
|
-
# rubocop:enable Style/Semicolon
|
408
|
-
|
409
|
-
after do
|
410
|
-
client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2})"
|
411
|
-
end
|
412
|
-
|
413
|
-
it "should return TrueClass or FalseClass for a BIT(1) value if :cast_booleans is enabled" do
|
414
|
-
query = client.prepare 'SELECT single_bit_test FROM mysql2_test WHERE id = ?'
|
415
|
-
result1 = query.execute id1
|
416
|
-
result2 = query.execute id2
|
417
|
-
expect(result1.first['single_bit_test']).to be true
|
418
|
-
expect(result2.first['single_bit_test']).to be false
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
it "should return Fixnum for a SMALLINT value" do
|
423
|
-
expect([Fixnum, Bignum]).to include(@test_result['small_int_test'].class)
|
424
|
-
expect(@test_result['small_int_test']).to eql(10)
|
425
|
-
end
|
426
|
-
|
427
|
-
it "should return Fixnum for a MEDIUMINT value" do
|
428
|
-
expect([Fixnum, Bignum]).to include(@test_result['medium_int_test'].class)
|
429
|
-
expect(@test_result['medium_int_test']).to eql(10)
|
430
|
-
end
|
431
|
-
|
432
|
-
it "should return Fixnum for an INT value" do
|
433
|
-
expect([Fixnum, Bignum]).to include(@test_result['int_test'].class)
|
434
|
-
expect(@test_result['int_test']).to eql(10)
|
435
|
-
end
|
436
|
-
|
437
|
-
it "should return Fixnum for a BIGINT value" do
|
438
|
-
expect([Fixnum, Bignum]).to include(@test_result['big_int_test'].class)
|
439
|
-
expect(@test_result['big_int_test']).to eql(10)
|
440
|
-
end
|
441
|
-
|
442
|
-
it "should return Fixnum for a YEAR value" do
|
443
|
-
expect([Fixnum, Bignum]).to include(@test_result['year_test'].class)
|
444
|
-
expect(@test_result['year_test']).to eql(2009)
|
445
|
-
end
|
446
|
-
|
447
|
-
it "should return BigDecimal for a DECIMAL value" do
|
448
|
-
expect(@test_result['decimal_test']).to be_an_instance_of(BigDecimal)
|
449
|
-
expect(@test_result['decimal_test']).to eql(10.3)
|
450
|
-
end
|
451
|
-
|
452
|
-
it "should return Float for a FLOAT value" do
|
453
|
-
expect(@test_result['float_test']).to be_an_instance_of(Float)
|
454
|
-
expect(@test_result['float_test']).to be_within(1e-5).of(10.3)
|
455
|
-
end
|
456
|
-
|
457
|
-
it "should return Float for a DOUBLE value" do
|
458
|
-
expect(@test_result['double_test']).to be_an_instance_of(Float)
|
459
|
-
expect(@test_result['double_test']).to eql(10.3)
|
460
|
-
end
|
461
|
-
|
462
|
-
it "should return Time for a DATETIME value when within the supported range" do
|
463
|
-
expect(@test_result['date_time_test']).to be_an_instance_of(Time)
|
464
|
-
expect(@test_result['date_time_test'].strftime("%Y-%m-%d %H:%M:%S")).to eql('2010-04-04 11:44:00')
|
465
|
-
end
|
466
|
-
|
467
|
-
if 1.size == 4 # 32bit
|
468
|
-
klass = if RUBY_VERSION =~ /1.8/
|
469
|
-
DateTime
|
470
|
-
else
|
471
|
-
Time
|
472
|
-
end
|
473
|
-
|
474
|
-
it "should return DateTime when timestamp is < 1901-12-13 20:45:52" do
|
475
|
-
# 1901-12-13T20:45:52 is the min for 32bit Ruby 1.8
|
476
|
-
r = @client.prepare("SELECT CAST('1901-12-13 20:45:51' AS DATETIME) as test").execute
|
477
|
-
expect(r.first['test']).to be_an_instance_of(klass)
|
478
|
-
end
|
479
|
-
|
480
|
-
it "should return DateTime when timestamp is > 2038-01-19T03:14:07" do
|
481
|
-
# 2038-01-19T03:14:07 is the max for 32bit Ruby 1.8
|
482
|
-
r = @client.prepare("SELECT CAST('2038-01-19 03:14:08' AS DATETIME) as test").execute
|
483
|
-
expect(r.first['test']).to be_an_instance_of(klass)
|
484
|
-
end
|
485
|
-
elsif 1.size == 8 # 64bit
|
486
|
-
if RUBY_VERSION =~ /1.8/
|
487
|
-
it "should return Time when timestamp is > 0138-12-31 11:59:59" do
|
488
|
-
r = @client.prepare("SELECT CAST('0139-1-1 00:00:00' AS DATETIME) as test").execute
|
489
|
-
expect(r.first['test']).to be_an_instance_of(Time)
|
490
|
-
end
|
491
|
-
|
492
|
-
it "should return DateTime when timestamp is < 0139-1-1T00:00:00" do
|
493
|
-
r = @client.prepare("SELECT CAST('0138-12-31 11:59:59' AS DATETIME) as test").execute
|
494
|
-
expect(r.first['test']).to be_an_instance_of(DateTime)
|
495
|
-
end
|
496
|
-
|
497
|
-
it "should return Time when timestamp is > 2038-01-19T03:14:07" do
|
498
|
-
r = @client.prepare("SELECT CAST('2038-01-19 03:14:08' AS DATETIME) as test").execute
|
499
|
-
expect(r.first['test']).to be_an_instance_of(Time)
|
500
|
-
end
|
501
|
-
else
|
502
|
-
it "should return Time when timestamp is < 1901-12-13 20:45:52" do
|
503
|
-
r = @client.prepare("SELECT CAST('1901-12-13 20:45:51' AS DATETIME) as test").execute
|
504
|
-
expect(r.first['test']).to be_an_instance_of(Time)
|
505
|
-
end
|
506
|
-
|
507
|
-
it "should return Time when timestamp is > 2038-01-19T03:14:07" do
|
508
|
-
r = @client.prepare("SELECT CAST('2038-01-19 03:14:08' AS DATETIME) as test").execute
|
509
|
-
expect(r.first['test']).to be_an_instance_of(Time)
|
510
|
-
end
|
511
|
-
end
|
512
|
-
end
|
513
|
-
|
514
|
-
it "should return Time for a TIMESTAMP value when within the supported range" do
|
515
|
-
expect(@test_result['timestamp_test']).to be_an_instance_of(Time)
|
516
|
-
expect(@test_result['timestamp_test'].strftime("%Y-%m-%d %H:%M:%S")).to eql('2010-04-04 11:44:00')
|
517
|
-
end
|
518
|
-
|
519
|
-
it "should return Time for a TIME value" do
|
520
|
-
expect(@test_result['time_test']).to be_an_instance_of(Time)
|
521
|
-
expect(@test_result['time_test'].strftime("%Y-%m-%d %H:%M:%S")).to eql('2000-01-01 11:44:00')
|
522
|
-
end
|
523
|
-
|
524
|
-
it "should return Date for a DATE value" do
|
525
|
-
expect(@test_result['date_test']).to be_an_instance_of(Date)
|
526
|
-
expect(@test_result['date_test'].strftime("%Y-%m-%d")).to eql('2010-04-04')
|
527
|
-
end
|
528
|
-
|
529
|
-
it "should return String for an ENUM value" do
|
530
|
-
expect(@test_result['enum_test']).to be_an_instance_of(String)
|
531
|
-
expect(@test_result['enum_test']).to eql('val1')
|
532
|
-
end
|
533
|
-
|
534
|
-
it "should raise an error given an invalid DATETIME" do
|
535
|
-
expect { @client.query("SELECT CAST('1972-00-27 00:00:00' AS DATETIME) as bad_datetime").each }.to \
|
536
|
-
raise_error(Mysql2::Error, "Invalid date in field 'bad_datetime': 1972-00-27 00:00:00")
|
537
|
-
end
|
538
|
-
|
539
|
-
context "string encoding for ENUM values" do
|
540
|
-
before { pending('Encoding is undefined') unless defined?(Encoding) }
|
541
|
-
|
542
|
-
it "should default to the connection's encoding if Encoding.default_internal is nil" do
|
543
|
-
with_internal_encoding nil do
|
544
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
545
|
-
expect(result['enum_test'].encoding).to eql(Encoding::UTF_8)
|
546
|
-
|
547
|
-
client2 = new_client(:encoding => 'ascii')
|
548
|
-
result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
549
|
-
expect(result['enum_test'].encoding).to eql(Encoding::US_ASCII)
|
550
|
-
end
|
551
|
-
end
|
552
|
-
|
553
|
-
it "should use Encoding.default_internal" do
|
554
|
-
with_internal_encoding Encoding::UTF_8 do
|
555
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
556
|
-
expect(result['enum_test'].encoding).to eql(Encoding.default_internal)
|
557
|
-
end
|
558
|
-
|
559
|
-
with_internal_encoding Encoding::ASCII do
|
560
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
561
|
-
expect(result['enum_test'].encoding).to eql(Encoding.default_internal)
|
562
|
-
end
|
563
|
-
end
|
564
|
-
end
|
565
|
-
|
566
|
-
it "should return String for a SET value" do
|
567
|
-
expect(@test_result['set_test']).to be_an_instance_of(String)
|
568
|
-
expect(@test_result['set_test']).to eql('val1,val2')
|
569
|
-
end
|
570
|
-
|
571
|
-
context "string encoding for SET values" do
|
572
|
-
before { pending('Encoding is undefined') unless defined?(Encoding) }
|
573
|
-
|
574
|
-
it "should default to the connection's encoding if Encoding.default_internal is nil" do
|
575
|
-
with_internal_encoding nil do
|
576
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
577
|
-
expect(result['set_test'].encoding).to eql(Encoding::UTF_8)
|
578
|
-
|
579
|
-
client2 = new_client(:encoding => 'ascii')
|
580
|
-
result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
581
|
-
expect(result['set_test'].encoding).to eql(Encoding::US_ASCII)
|
582
|
-
end
|
583
|
-
end
|
584
|
-
|
585
|
-
it "should use Encoding.default_internal" do
|
586
|
-
with_internal_encoding Encoding::UTF_8 do
|
587
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
588
|
-
expect(result['set_test'].encoding).to eql(Encoding.default_internal)
|
589
|
-
end
|
590
|
-
|
591
|
-
with_internal_encoding Encoding::ASCII do
|
592
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
593
|
-
expect(result['set_test'].encoding).to eql(Encoding.default_internal)
|
594
|
-
end
|
595
|
-
end
|
596
|
-
end
|
597
|
-
|
598
|
-
it "should return String for a BINARY value" do
|
599
|
-
expect(@test_result['binary_test']).to be_an_instance_of(String)
|
600
|
-
expect(@test_result['binary_test']).to eql("test#{"\000" * 6}")
|
601
|
-
end
|
602
|
-
|
603
|
-
context "string encoding for BINARY values" do
|
604
|
-
before { pending('Encoding is undefined') unless defined?(Encoding) }
|
605
|
-
|
606
|
-
it "should default to binary if Encoding.default_internal is nil" do
|
607
|
-
with_internal_encoding nil do
|
608
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
609
|
-
expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
|
610
|
-
end
|
611
|
-
end
|
612
|
-
|
613
|
-
it "should not use Encoding.default_internal" do
|
614
|
-
with_internal_encoding Encoding::UTF_8 do
|
615
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
616
|
-
expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
|
617
|
-
end
|
618
|
-
|
619
|
-
with_internal_encoding Encoding::ASCII do
|
620
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
621
|
-
expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
|
622
|
-
end
|
623
|
-
end
|
624
|
-
end
|
625
|
-
|
626
|
-
{
|
627
|
-
'char_test' => 'CHAR',
|
628
|
-
'varchar_test' => 'VARCHAR',
|
629
|
-
'varbinary_test' => 'VARBINARY',
|
630
|
-
'tiny_blob_test' => 'TINYBLOB',
|
631
|
-
'tiny_text_test' => 'TINYTEXT',
|
632
|
-
'blob_test' => 'BLOB',
|
633
|
-
'text_test' => 'TEXT',
|
634
|
-
'medium_blob_test' => 'MEDIUMBLOB',
|
635
|
-
'medium_text_test' => 'MEDIUMTEXT',
|
636
|
-
'long_blob_test' => 'LONGBLOB',
|
637
|
-
'long_text_test' => 'LONGTEXT',
|
638
|
-
}.each do |field, type|
|
639
|
-
it "should return a String for #{type}" do
|
640
|
-
expect(@test_result[field]).to be_an_instance_of(String)
|
641
|
-
expect(@test_result[field]).to eql("test")
|
642
|
-
end
|
643
|
-
|
644
|
-
context "string encoding for #{type} values" do
|
645
|
-
before { pending('Encoding is undefined') unless defined?(Encoding) }
|
646
|
-
|
647
|
-
if %w(VARBINARY TINYBLOB BLOB MEDIUMBLOB LONGBLOB).include?(type)
|
648
|
-
it "should default to binary if Encoding.default_internal is nil" do
|
649
|
-
with_internal_encoding nil do
|
650
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
651
|
-
expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
|
652
|
-
end
|
653
|
-
end
|
654
|
-
|
655
|
-
it "should not use Encoding.default_internal" do
|
656
|
-
with_internal_encoding Encoding::UTF_8 do
|
657
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
658
|
-
expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
|
659
|
-
end
|
660
|
-
|
661
|
-
with_internal_encoding Encoding::ASCII do
|
662
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
663
|
-
expect(result['binary_test'].encoding).to eql(Encoding::BINARY)
|
664
|
-
end
|
665
|
-
end
|
666
|
-
else
|
667
|
-
it "should default to utf-8 if Encoding.default_internal is nil" do
|
668
|
-
with_internal_encoding nil do
|
669
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
670
|
-
expect(result[field].encoding).to eql(Encoding::UTF_8)
|
671
|
-
|
672
|
-
client2 = new_client(:encoding => 'ascii')
|
673
|
-
result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
674
|
-
expect(result[field].encoding).to eql(Encoding::US_ASCII)
|
675
|
-
end
|
676
|
-
end
|
677
|
-
|
678
|
-
it "should use Encoding.default_internal" do
|
679
|
-
with_internal_encoding Encoding::UTF_8 do
|
680
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
681
|
-
expect(result[field].encoding).to eql(Encoding.default_internal)
|
682
|
-
end
|
683
|
-
|
684
|
-
with_internal_encoding Encoding::ASCII do
|
685
|
-
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
686
|
-
expect(result[field].encoding).to eql(Encoding.default_internal)
|
687
|
-
end
|
688
|
-
end
|
689
|
-
end
|
690
|
-
end
|
691
|
-
end
|
692
|
-
end
|
693
|
-
|
694
|
-
context 'last_id' do
|
695
|
-
before(:each) do
|
696
|
-
@client.query 'USE test'
|
697
|
-
@client.query 'CREATE TABLE IF NOT EXISTS lastIdTest (`id` BIGINT NOT NULL AUTO_INCREMENT, blah INT(11), PRIMARY KEY (`id`))'
|
698
|
-
end
|
699
|
-
|
700
|
-
after(:each) do
|
701
|
-
@client.query 'DROP TABLE lastIdTest'
|
702
|
-
end
|
703
|
-
|
704
|
-
it 'should return last insert id' do
|
705
|
-
stmt = @client.prepare 'INSERT INTO lastIdTest (blah) VALUES (?)'
|
706
|
-
expect(stmt.last_id).to eq 0
|
707
|
-
stmt.execute 1
|
708
|
-
expect(stmt.last_id).to eq 1
|
709
|
-
end
|
710
|
-
|
711
|
-
it 'should handle bigint ids' do
|
712
|
-
stmt = @client.prepare 'INSERT INTO lastIdTest (id, blah) VALUES (?, ?)'
|
713
|
-
stmt.execute 5000000000, 5000
|
714
|
-
expect(stmt.last_id).to eql(5000000000)
|
715
|
-
|
716
|
-
stmt = @client.prepare 'INSERT INTO lastIdTest (blah) VALUES (?)'
|
717
|
-
stmt.execute 5001
|
718
|
-
expect(stmt.last_id).to eql(5000000001)
|
719
|
-
end
|
720
|
-
end
|
721
|
-
|
722
|
-
context 'affected_rows' do
|
723
|
-
before :each do
|
724
|
-
@client.query 'USE test'
|
725
|
-
@client.query 'CREATE TABLE IF NOT EXISTS lastIdTest (`id` BIGINT NOT NULL AUTO_INCREMENT, blah INT(11), PRIMARY KEY (`id`))'
|
726
|
-
end
|
727
|
-
|
728
|
-
after :each do
|
729
|
-
@client.query 'DROP TABLE lastIdTest'
|
730
|
-
end
|
731
|
-
|
732
|
-
it 'should return number of rows affected by an insert' do
|
733
|
-
stmt = @client.prepare 'INSERT INTO lastIdTest (blah) VALUES (?)'
|
734
|
-
expect(stmt.affected_rows).to eq 0
|
735
|
-
stmt.execute 1
|
736
|
-
expect(stmt.affected_rows).to eq 1
|
737
|
-
end
|
738
|
-
|
739
|
-
it 'should return number of rows affected by an update' do
|
740
|
-
stmt = @client.prepare 'INSERT INTO lastIdTest (blah) VALUES (?)'
|
741
|
-
stmt.execute 1
|
742
|
-
expect(stmt.affected_rows).to eq 1
|
743
|
-
stmt.execute 2
|
744
|
-
expect(stmt.affected_rows).to eq 1
|
745
|
-
|
746
|
-
stmt = @client.prepare 'UPDATE lastIdTest SET blah=? WHERE blah=?'
|
747
|
-
stmt.execute 0, 1
|
748
|
-
expect(stmt.affected_rows).to eq 1
|
749
|
-
end
|
750
|
-
|
751
|
-
it 'should return number of rows affected by a delete' do
|
752
|
-
stmt = @client.prepare 'INSERT INTO lastIdTest (blah) VALUES (?)'
|
753
|
-
stmt.execute 1
|
754
|
-
expect(stmt.affected_rows).to eq 1
|
755
|
-
stmt.execute 2
|
756
|
-
expect(stmt.affected_rows).to eq 1
|
757
|
-
|
758
|
-
stmt = @client.prepare 'DELETE FROM lastIdTest WHERE blah=?'
|
759
|
-
stmt.execute 1
|
760
|
-
expect(stmt.affected_rows).to eq 1
|
761
|
-
end
|
762
|
-
end
|
763
|
-
|
764
|
-
context 'close' do
|
765
|
-
it 'should free server resources' do
|
766
|
-
stmt = @client.prepare 'SELECT 1'
|
767
|
-
expect { stmt.close }.to change(&method(:stmt_count)).by(-1)
|
768
|
-
end
|
769
|
-
|
770
|
-
it 'should raise an error on subsequent execution' do
|
771
|
-
stmt = @client.prepare 'SELECT 1'
|
772
|
-
stmt.close
|
773
|
-
expect { stmt.execute }.to raise_error(Mysql2::Error, /Invalid statement handle/)
|
774
|
-
end
|
775
|
-
end
|
776
|
-
end
|