mysql2 0.2.6-x86-mingw32
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.
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +117 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +240 -0
- data/Rakefile +5 -0
- data/VERSION +1 -0
- data/benchmark/active_record.rb +53 -0
- data/benchmark/allocations.rb +33 -0
- data/benchmark/escape.rb +39 -0
- data/benchmark/query_with_mysql_casting.rb +83 -0
- data/benchmark/query_without_mysql_casting.rb +50 -0
- data/benchmark/sequel.rb +39 -0
- data/benchmark/setup_db.rb +115 -0
- data/examples/eventmachine.rb +21 -0
- data/examples/threaded.rb +20 -0
- data/ext/mysql2/client.c +659 -0
- data/ext/mysql2/client.h +41 -0
- data/ext/mysql2/extconf.rb +65 -0
- data/ext/mysql2/mysql2_ext.c +12 -0
- data/ext/mysql2/mysql2_ext.h +32 -0
- data/ext/mysql2/result.c +475 -0
- data/ext/mysql2/result.h +20 -0
- data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +63 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +654 -0
- data/lib/active_record/fiber_patches.rb +104 -0
- data/lib/arel/engines/sql/compilers/mysql2_compiler.rb +11 -0
- data/lib/mysql2.rb +16 -0
- data/lib/mysql2/client.rb +235 -0
- data/lib/mysql2/em.rb +33 -0
- data/lib/mysql2/error.rb +15 -0
- data/lib/mysql2/result.rb +5 -0
- data/mysql2.gemspec +89 -0
- data/spec/em/em_spec.rb +49 -0
- data/spec/mysql2/client_spec.rb +348 -0
- data/spec/mysql2/error_spec.rb +25 -0
- data/spec/mysql2/result_spec.rb +318 -0
- data/spec/rcov.opts +3 -0
- data/spec/spec_helper.rb +67 -0
- data/tasks/benchmarks.rake +8 -0
- data/tasks/compile.rake +54 -0
- data/tasks/jeweler.rake +17 -0
- data/tasks/rspec.rake +16 -0
- data/tasks/vendor_mysql.rake +41 -0
- metadata +120 -0
data/spec/em/em_spec.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
if defined? EventMachine
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'mysql2/em'
|
5
|
+
|
6
|
+
describe Mysql2::EM::Client do
|
7
|
+
it "should support async queries" do
|
8
|
+
results = []
|
9
|
+
EM.run do
|
10
|
+
client1 = Mysql2::EM::Client.new
|
11
|
+
defer1 = client1.query "SELECT sleep(0.1) as first_query"
|
12
|
+
defer1.callback do |result|
|
13
|
+
results << result.first
|
14
|
+
EM.stop_event_loop
|
15
|
+
end
|
16
|
+
|
17
|
+
client2 = Mysql2::EM::Client.new
|
18
|
+
defer2 = client2.query "SELECT sleep(0.025) second_query"
|
19
|
+
defer2.callback do |result|
|
20
|
+
results << result.first
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
results[0].keys.should include("second_query")
|
25
|
+
results[1].keys.should include("first_query")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should support queries in callbacks" do
|
29
|
+
results = []
|
30
|
+
EM.run do
|
31
|
+
client = Mysql2::EM::Client.new
|
32
|
+
defer1 = client.query "SELECT sleep(0.025) as first_query"
|
33
|
+
defer1.callback do |result|
|
34
|
+
results << result.first
|
35
|
+
defer2 = client.query "SELECT sleep(0.025) as second_query"
|
36
|
+
defer2.callback do |result|
|
37
|
+
results << result.first
|
38
|
+
EM.stop_event_loop
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
results[0].keys.should include("first_query")
|
44
|
+
results[1].keys.should include("second_query")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
else
|
48
|
+
puts "EventMachine not installed, skipping the specs that use it"
|
49
|
+
end
|
@@ -0,0 +1,348 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Mysql2::Client do
|
5
|
+
before(:each) do
|
6
|
+
@client = Mysql2::Client.new
|
7
|
+
end
|
8
|
+
|
9
|
+
if defined? Encoding
|
10
|
+
it "should raise an exception on create for invalid encodings" do
|
11
|
+
lambda {
|
12
|
+
c = Mysql2::Client.new(:encoding => "fake")
|
13
|
+
}.should raise_error(Mysql2::Error)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should accept connect flags and pass them to #connect" do
|
18
|
+
klient = Class.new(Mysql2::Client) do
|
19
|
+
attr_reader :connect_args
|
20
|
+
def connect *args
|
21
|
+
@connect_args ||= []
|
22
|
+
@connect_args << args
|
23
|
+
end
|
24
|
+
end
|
25
|
+
client = klient.new :flags => Mysql2::Client::FOUND_ROWS
|
26
|
+
(client.connect_args.last.last & Mysql2::Client::FOUND_ROWS).should be_true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should default flags to (REMEMBER_OPTIONS, LONG_PASSWORD, LONG_FLAG, TRANSACTIONS, PROTOCOL_41, SECURE_CONNECTION)" do
|
30
|
+
klient = Class.new(Mysql2::Client) do
|
31
|
+
attr_reader :connect_args
|
32
|
+
def connect *args
|
33
|
+
@connect_args ||= []
|
34
|
+
@connect_args << args
|
35
|
+
end
|
36
|
+
end
|
37
|
+
client = klient.new
|
38
|
+
(client.connect_args.last.last & (Mysql2::Client::REMEMBER_OPTIONS |
|
39
|
+
Mysql2::Client::LONG_PASSWORD |
|
40
|
+
Mysql2::Client::LONG_FLAG |
|
41
|
+
Mysql2::Client::TRANSACTIONS |
|
42
|
+
Mysql2::Client::PROTOCOL_41 |
|
43
|
+
Mysql2::Client::SECURE_CONNECTION)).should be_true
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should have a global default_query_options hash" do
|
47
|
+
Mysql2::Client.should respond_to(:default_query_options)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should be able to connect via SSL options" do
|
51
|
+
pending("DON'T WORRY, THIS TEST PASSES :) - but is machine-specific. You need to have MySQL running with SSL configured and enabled. Then update the paths in this test to your needs and remove the pending state.")
|
52
|
+
ssl_client = nil
|
53
|
+
lambda {
|
54
|
+
ssl_client = Mysql2::Client.new(
|
55
|
+
:sslkey => '/path/to/client-key.pem',
|
56
|
+
:sslcert => '/path/to/client-cert.pem',
|
57
|
+
:sslca => '/path/to/ca-cert.pem',
|
58
|
+
:sslcapath => '/path/to/newcerts/',
|
59
|
+
:sslcipher => 'DHE-RSA-AES256-SHA'
|
60
|
+
)
|
61
|
+
}.should_not raise_error(Mysql2::Error)
|
62
|
+
|
63
|
+
results = ssl_client.query("SHOW STATUS WHERE Variable_name = \"Ssl_version\" OR Variable_name = \"Ssl_cipher\"").to_a
|
64
|
+
results[0]['Variable_name'].should eql('Ssl_cipher')
|
65
|
+
results[0]['Value'].should_not be_nil
|
66
|
+
results[0]['Value'].class.should eql(String)
|
67
|
+
|
68
|
+
results[1]['Variable_name'].should eql('Ssl_version')
|
69
|
+
results[1]['Value'].should_not be_nil
|
70
|
+
results[1]['Value'].class.should eql(String)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should respond to #close" do
|
74
|
+
@client.should respond_to(:close)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should be able to close properly" do
|
78
|
+
@client.close.should be_nil
|
79
|
+
lambda {
|
80
|
+
@client.query "SELECT 1"
|
81
|
+
}.should raise_error(Mysql2::Error)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should respond to #query" do
|
85
|
+
@client.should respond_to(:query)
|
86
|
+
end
|
87
|
+
|
88
|
+
context "#query" do
|
89
|
+
it "should accept an options hash that inherits from Mysql2::Client.default_query_options" do
|
90
|
+
@client.query "SELECT 1", :something => :else
|
91
|
+
@client.query_options.should eql(@client.query_options.merge(:something => :else))
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should return results as a hash by default" do
|
95
|
+
@client.query("SELECT 1").first.class.should eql(Hash)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should be able to return results as an array" do
|
99
|
+
@client.query("SELECT 1", :as => :array).first.class.should eql(Array)
|
100
|
+
@client.query("SELECT 1").each(:as => :array)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should be able to return results with symbolized keys" do
|
104
|
+
@client.query("SELECT 1", :symbolize_keys => true).first.keys[0].class.should eql(Symbol)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should not allow another query to be sent without fetching a result first" do
|
108
|
+
@client.query("SELECT 1", :async => true)
|
109
|
+
lambda {
|
110
|
+
@client.query("SELECT 1")
|
111
|
+
}.should raise_error(Mysql2::Error)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should require an open connection" do
|
115
|
+
@client.close
|
116
|
+
lambda {
|
117
|
+
@client.query "SELECT 1"
|
118
|
+
}.should raise_error(Mysql2::Error)
|
119
|
+
end
|
120
|
+
|
121
|
+
# XXX this test is not deterministic (because Unix signal handling is not)
|
122
|
+
# and may fail on a loaded system
|
123
|
+
if RUBY_PLATFORM !~ /mingw|mswin/
|
124
|
+
it "should run signal handlers while waiting for a response" do
|
125
|
+
mark = {}
|
126
|
+
trap(:USR1) { mark[:USR1] = Time.now }
|
127
|
+
begin
|
128
|
+
mark[:START] = Time.now
|
129
|
+
pid = fork do
|
130
|
+
sleep 1 # wait for client "SELECT sleep(2)" query to start
|
131
|
+
Process.kill(:USR1, Process.ppid)
|
132
|
+
sleep # wait for explicit kill to prevent GC disconnect
|
133
|
+
end
|
134
|
+
@client.query("SELECT sleep(2)")
|
135
|
+
mark[:END] = Time.now
|
136
|
+
mark.include?(:USR1).should be_true
|
137
|
+
(mark[:USR1] - mark[:START]).should >= 1
|
138
|
+
(mark[:USR1] - mark[:START]).should < 1.1
|
139
|
+
(mark[:END] - mark[:USR1]).should > 0.9
|
140
|
+
(mark[:END] - mark[:START]).should >= 2
|
141
|
+
(mark[:END] - mark[:START]).should < 2.1
|
142
|
+
Process.kill(:TERM, pid)
|
143
|
+
Process.waitpid2(pid)
|
144
|
+
ensure
|
145
|
+
trap(:USR1, 'DEFAULT')
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should respond to #escape" do
|
152
|
+
@client.should respond_to(:escape)
|
153
|
+
end
|
154
|
+
|
155
|
+
context "#escape" do
|
156
|
+
it "should return a new SQL-escape version of the passed string" do
|
157
|
+
@client.escape("abc'def\"ghi\0jkl%mno").should eql("abc\\'def\\\"ghi\\0jkl%mno")
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should return the passed string if nothing was escaped" do
|
161
|
+
str = "plain"
|
162
|
+
@client.escape(str).object_id.should eql(str.object_id)
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should not overflow the thread stack" do
|
166
|
+
lambda {
|
167
|
+
Thread.new { @client.escape("'" * 256 * 1024) }.join
|
168
|
+
}.should_not raise_error(SystemStackError)
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should not overflow the process stack" do
|
172
|
+
lambda {
|
173
|
+
Thread.new { @client.escape("'" * 1024 * 1024 * 4) }.join
|
174
|
+
}.should_not raise_error(SystemStackError)
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should require an open connection" do
|
178
|
+
@client.close
|
179
|
+
lambda {
|
180
|
+
@client.escape ""
|
181
|
+
}.should raise_error(Mysql2::Error)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should respond to #info" do
|
186
|
+
@client.should respond_to(:info)
|
187
|
+
end
|
188
|
+
|
189
|
+
it "#info should return a hash containing the client version ID and String" do
|
190
|
+
info = @client.info
|
191
|
+
info.class.should eql(Hash)
|
192
|
+
info.should have_key(:id)
|
193
|
+
info[:id].class.should eql(Fixnum)
|
194
|
+
info.should have_key(:version)
|
195
|
+
info[:version].class.should eql(String)
|
196
|
+
end
|
197
|
+
|
198
|
+
if defined? Encoding
|
199
|
+
context "strings returned by #info" do
|
200
|
+
it "should default to the connection's encoding if Encoding.default_internal is nil" do
|
201
|
+
Encoding.default_internal = nil
|
202
|
+
@client.info[:version].encoding.should eql(Encoding.find('utf-8'))
|
203
|
+
|
204
|
+
client2 = Mysql2::Client.new :encoding => 'ascii'
|
205
|
+
client2.info[:version].encoding.should eql(Encoding.find('us-ascii'))
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should use Encoding.default_internal" do
|
209
|
+
Encoding.default_internal = Encoding.find('utf-8')
|
210
|
+
@client.info[:version].encoding.should eql(Encoding.default_internal)
|
211
|
+
Encoding.default_internal = Encoding.find('us-ascii')
|
212
|
+
@client.info[:version].encoding.should eql(Encoding.default_internal)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should respond to #server_info" do
|
218
|
+
@client.should respond_to(:server_info)
|
219
|
+
end
|
220
|
+
|
221
|
+
it "#server_info should return a hash containing the client version ID and String" do
|
222
|
+
server_info = @client.server_info
|
223
|
+
server_info.class.should eql(Hash)
|
224
|
+
server_info.should have_key(:id)
|
225
|
+
server_info[:id].class.should eql(Fixnum)
|
226
|
+
server_info.should have_key(:version)
|
227
|
+
server_info[:version].class.should eql(String)
|
228
|
+
end
|
229
|
+
|
230
|
+
it "#server_info should require an open connection" do
|
231
|
+
@client.close
|
232
|
+
lambda {
|
233
|
+
@client.server_info
|
234
|
+
}.should raise_error(Mysql2::Error)
|
235
|
+
end
|
236
|
+
|
237
|
+
if defined? Encoding
|
238
|
+
context "strings returned by #server_info" do
|
239
|
+
it "should default to the connection's encoding if Encoding.default_internal is nil" do
|
240
|
+
Encoding.default_internal = nil
|
241
|
+
@client.server_info[:version].encoding.should eql(Encoding.find('utf-8'))
|
242
|
+
|
243
|
+
client2 = Mysql2::Client.new :encoding => 'ascii'
|
244
|
+
client2.server_info[:version].encoding.should eql(Encoding.find('us-ascii'))
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should use Encoding.default_internal" do
|
248
|
+
Encoding.default_internal = Encoding.find('utf-8')
|
249
|
+
@client.server_info[:version].encoding.should eql(Encoding.default_internal)
|
250
|
+
Encoding.default_internal = Encoding.find('us-ascii')
|
251
|
+
@client.server_info[:version].encoding.should eql(Encoding.default_internal)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should respond to #socket" do
|
257
|
+
@client.should respond_to(:socket)
|
258
|
+
end
|
259
|
+
|
260
|
+
it "#socket should return a Fixnum (file descriptor from C)" do
|
261
|
+
@client.socket.class.should eql(Fixnum)
|
262
|
+
@client.socket.should_not eql(0)
|
263
|
+
end
|
264
|
+
|
265
|
+
it "#socket should require an open connection" do
|
266
|
+
@client.close
|
267
|
+
lambda {
|
268
|
+
@client.socket
|
269
|
+
}.should raise_error(Mysql2::Error)
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should raise a Mysql2::Error exception upon connection failure" do
|
273
|
+
lambda {
|
274
|
+
bad_client = Mysql2::Client.new :host => "dfjhdi9wrhw", :username => 'asdfasdf8d2h'
|
275
|
+
}.should raise_error(Mysql2::Error)
|
276
|
+
|
277
|
+
lambda {
|
278
|
+
good_client = Mysql2::Client.new
|
279
|
+
}.should_not raise_error(Mysql2::Error)
|
280
|
+
end
|
281
|
+
|
282
|
+
it "threaded queries should be supported" do
|
283
|
+
threads, results = [], {}
|
284
|
+
connect = lambda{ Mysql2::Client.new(:host => "localhost", :username => "root") }
|
285
|
+
Timeout.timeout(0.7) do
|
286
|
+
5.times {
|
287
|
+
threads << Thread.new do
|
288
|
+
results[Thread.current.object_id] = connect.call.query("SELECT sleep(0.5) as result")
|
289
|
+
end
|
290
|
+
}
|
291
|
+
end
|
292
|
+
threads.each{|t| t.join }
|
293
|
+
results.keys.sort.should eql(threads.map{|t| t.object_id }.sort)
|
294
|
+
end
|
295
|
+
|
296
|
+
it "evented async queries should be supported" do
|
297
|
+
# should immediately return nil
|
298
|
+
@client.query("SELECT sleep(0.1)", :async => true).should eql(nil)
|
299
|
+
|
300
|
+
io_wrapper = IO.for_fd(@client.socket)
|
301
|
+
loops = 0
|
302
|
+
loop do
|
303
|
+
if IO.select([io_wrapper], nil, nil, 0.05)
|
304
|
+
break
|
305
|
+
else
|
306
|
+
loops += 1
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
# make sure we waited some period of time
|
311
|
+
(loops >= 1).should be_true
|
312
|
+
|
313
|
+
result = @client.async_result
|
314
|
+
result.class.should eql(Mysql2::Result)
|
315
|
+
end
|
316
|
+
|
317
|
+
context 'write operations api' do
|
318
|
+
before(:each) do
|
319
|
+
@client.query "USE test"
|
320
|
+
@client.query "CREATE TABLE lastIdTest (`id` int(11) NOT NULL AUTO_INCREMENT, blah INT(11), PRIMARY KEY (`id`))"
|
321
|
+
end
|
322
|
+
|
323
|
+
after(:each) do
|
324
|
+
@client.query "DROP TABLE lastIdTest"
|
325
|
+
end
|
326
|
+
|
327
|
+
it "should respond to #last_id" do
|
328
|
+
@client.should respond_to(:last_id)
|
329
|
+
end
|
330
|
+
|
331
|
+
it "#last_id should return a Fixnum, the from the last INSERT/UPDATE" do
|
332
|
+
@client.last_id.should eql(0)
|
333
|
+
@client.query "INSERT INTO lastIdTest (blah) VALUES (1234)"
|
334
|
+
@client.last_id.should eql(1)
|
335
|
+
end
|
336
|
+
|
337
|
+
it "should respond to #last_id" do
|
338
|
+
@client.should respond_to(:last_id)
|
339
|
+
end
|
340
|
+
|
341
|
+
it "#last_id should return a Fixnum, the from the last INSERT/UPDATE" do
|
342
|
+
@client.query "INSERT INTO lastIdTest (blah) VALUES (1234)"
|
343
|
+
@client.affected_rows.should eql(1)
|
344
|
+
@client.query "UPDATE lastIdTest SET blah=4321 WHERE id=1"
|
345
|
+
@client.affected_rows.should eql(1)
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Mysql2::Error do
|
5
|
+
before(:each) do
|
6
|
+
@error = Mysql2::Error.new "testing"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should respond to #error_number" do
|
10
|
+
@error.should respond_to(:error_number)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should respond to #sql_state" do
|
14
|
+
@error.should respond_to(:sql_state)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Mysql gem compatibility
|
18
|
+
it "should alias #error_number to #errno" do
|
19
|
+
@error.should respond_to(:errno)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should alias #message to #error" do
|
23
|
+
@error.should respond_to(:error)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,318 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Mysql2::Result do
|
5
|
+
before(:each) do
|
6
|
+
@client = Mysql2::Client.new :host => "localhost", :username => "root"
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
@result = @client.query "SELECT 1"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have included Enumerable" do
|
14
|
+
Mysql2::Result.ancestors.include?(Enumerable).should be_true
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should respond to #each" do
|
18
|
+
@result.should respond_to(:each)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should raise a Mysql2::Error exception upon a bad query" do
|
22
|
+
lambda {
|
23
|
+
@client.query "bad sql"
|
24
|
+
}.should raise_error(Mysql2::Error)
|
25
|
+
|
26
|
+
lambda {
|
27
|
+
@client.query "SELECT 1"
|
28
|
+
}.should_not raise_error(Mysql2::Error)
|
29
|
+
end
|
30
|
+
|
31
|
+
context "#each" do
|
32
|
+
it "should yield rows as hash's" do
|
33
|
+
@result.each do |row|
|
34
|
+
row.class.should eql(Hash)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
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)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should be able to return results as an array" do
|
45
|
+
@result.each(:as => :array) do |row|
|
46
|
+
row.class.should eql(Array)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should cache previously yielded results by default" do
|
51
|
+
@result.first.object_id.should eql(@result.first.object_id)
|
52
|
+
end
|
53
|
+
|
54
|
+
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)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
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
|
65
|
+
|
66
|
+
it "method should exist" do
|
67
|
+
@test_result.should respond_to(:fields)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should return an array of field names in proper order" do
|
71
|
+
result = @client.query "SELECT 'a', 'b', 'c'"
|
72
|
+
result.fields.should eql(['a', 'b', 'c'])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "row data type mapping" do
|
77
|
+
before(:each) do
|
78
|
+
@client.query "USE test"
|
79
|
+
@test_result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
80
|
+
end
|
81
|
+
|
82
|
+
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)
|
85
|
+
end
|
86
|
+
|
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")
|
90
|
+
end
|
91
|
+
|
92
|
+
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)
|
95
|
+
end
|
96
|
+
|
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
|
102
|
+
|
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
|
107
|
+
|
108
|
+
@client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2})"
|
109
|
+
end
|
110
|
+
|
111
|
+
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)
|
114
|
+
end
|
115
|
+
|
116
|
+
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)
|
119
|
+
end
|
120
|
+
|
121
|
+
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)
|
124
|
+
end
|
125
|
+
|
126
|
+
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)
|
129
|
+
end
|
130
|
+
|
131
|
+
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)
|
134
|
+
end
|
135
|
+
|
136
|
+
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)
|
139
|
+
end
|
140
|
+
|
141
|
+
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)
|
144
|
+
end
|
145
|
+
|
146
|
+
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)
|
149
|
+
end
|
150
|
+
|
151
|
+
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')
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should return DateTime for a DATETIME value when outside the supported range" do
|
157
|
+
r = @client.query("SELECT CAST('1901-1-1 01:01:01' AS DATETIME) as test")
|
158
|
+
r.first['test'].class.should eql(DateTime)
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should return Time for a TIMESTAMP value when within the supported range" do
|
162
|
+
@test_result['timestamp_test'].class.should eql(Time)
|
163
|
+
@test_result['timestamp_test'].strftime("%F %T").should eql('2010-04-04 11:44:00')
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should return Time for a TIME value" do
|
167
|
+
@test_result['time_test'].class.should eql(Time)
|
168
|
+
@test_result['time_test'].strftime("%F %T").should eql('2000-01-01 11:44:00')
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should return Date for a DATE value" do
|
172
|
+
@test_result['date_test'].class.should eql(Date)
|
173
|
+
@test_result['date_test'].strftime("%F").should eql('2010-04-04')
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should return String for an ENUM value" do
|
177
|
+
@test_result['enum_test'].class.should eql(String)
|
178
|
+
@test_result['enum_test'].should eql('val1')
|
179
|
+
end
|
180
|
+
|
181
|
+
if defined? Encoding
|
182
|
+
context "string encoding for ENUM values" do
|
183
|
+
it "should default to the connection's encoding if Encoding.default_internal is nil" do
|
184
|
+
Encoding.default_internal = nil
|
185
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
186
|
+
result['enum_test'].encoding.should eql(Encoding.find('utf-8'))
|
187
|
+
|
188
|
+
client2 = Mysql2::Client.new :encoding => 'ascii'
|
189
|
+
client2.query "USE test"
|
190
|
+
result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
191
|
+
result['enum_test'].encoding.should eql(Encoding.find('us-ascii'))
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should use Encoding.default_internal" do
|
195
|
+
Encoding.default_internal = Encoding.find('utf-8')
|
196
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
197
|
+
result['enum_test'].encoding.should eql(Encoding.default_internal)
|
198
|
+
Encoding.default_internal = Encoding.find('us-ascii')
|
199
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
200
|
+
result['enum_test'].encoding.should eql(Encoding.default_internal)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should return String for a SET value" do
|
206
|
+
@test_result['set_test'].class.should eql(String)
|
207
|
+
@test_result['set_test'].should eql('val1,val2')
|
208
|
+
end
|
209
|
+
|
210
|
+
if defined? Encoding
|
211
|
+
context "string encoding for SET values" do
|
212
|
+
it "should default to the connection's encoding if Encoding.default_internal is nil" do
|
213
|
+
Encoding.default_internal = nil
|
214
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
215
|
+
result['set_test'].encoding.should eql(Encoding.find('utf-8'))
|
216
|
+
|
217
|
+
client2 = Mysql2::Client.new :encoding => 'ascii'
|
218
|
+
client2.query "USE test"
|
219
|
+
result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
220
|
+
result['set_test'].encoding.should eql(Encoding.find('us-ascii'))
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should use Encoding.default_internal" do
|
224
|
+
Encoding.default_internal = Encoding.find('utf-8')
|
225
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
226
|
+
result['set_test'].encoding.should eql(Encoding.default_internal)
|
227
|
+
Encoding.default_internal = Encoding.find('us-ascii')
|
228
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
229
|
+
result['set_test'].encoding.should eql(Encoding.default_internal)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should return String for a BINARY value" do
|
235
|
+
@test_result['binary_test'].class.should eql(String)
|
236
|
+
@test_result['binary_test'].should eql("test#{"\000"*6}")
|
237
|
+
end
|
238
|
+
|
239
|
+
if defined? Encoding
|
240
|
+
context "string encoding for BINARY values" do
|
241
|
+
it "should default to binary if Encoding.default_internal is nil" do
|
242
|
+
Encoding.default_internal = nil
|
243
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
244
|
+
result['binary_test'].encoding.should eql(Encoding.find('binary'))
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should not use Encoding.default_internal" do
|
248
|
+
Encoding.default_internal = Encoding.find('utf-8')
|
249
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
250
|
+
result['binary_test'].encoding.should eql(Encoding.find('binary'))
|
251
|
+
Encoding.default_internal = Encoding.find('us-ascii')
|
252
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
253
|
+
result['binary_test'].encoding.should eql(Encoding.find('binary'))
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
{
|
259
|
+
'char_test' => 'CHAR',
|
260
|
+
'varchar_test' => 'VARCHAR',
|
261
|
+
'varbinary_test' => 'VARBINARY',
|
262
|
+
'tiny_blob_test' => 'TINYBLOB',
|
263
|
+
'tiny_text_test' => 'TINYTEXT',
|
264
|
+
'blob_test' => 'BLOB',
|
265
|
+
'text_test' => 'TEXT',
|
266
|
+
'medium_blob_test' => 'MEDIUMBLOB',
|
267
|
+
'medium_text_test' => 'MEDIUMTEXT',
|
268
|
+
'long_blob_test' => 'LONGBLOB',
|
269
|
+
'long_text_test' => 'LONGTEXT'
|
270
|
+
}.each do |field, type|
|
271
|
+
it "should return a String for #{type}" do
|
272
|
+
@test_result[field].class.should eql(String)
|
273
|
+
@test_result[field].should eql("test")
|
274
|
+
end
|
275
|
+
|
276
|
+
if defined? Encoding
|
277
|
+
context "string encoding for #{type} values" do
|
278
|
+
if ['VARBINARY', 'TINYBLOB', 'BLOB', 'MEDIUMBLOB', 'LONGBLOB'].include?(type)
|
279
|
+
it "should default to binary if Encoding.default_internal is nil" do
|
280
|
+
Encoding.default_internal = nil
|
281
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
282
|
+
result['binary_test'].encoding.should eql(Encoding.find('binary'))
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should not use Encoding.default_internal" do
|
286
|
+
Encoding.default_internal = Encoding.find('utf-8')
|
287
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
288
|
+
result['binary_test'].encoding.should eql(Encoding.find('binary'))
|
289
|
+
Encoding.default_internal = Encoding.find('us-ascii')
|
290
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
291
|
+
result['binary_test'].encoding.should eql(Encoding.find('binary'))
|
292
|
+
end
|
293
|
+
else
|
294
|
+
it "should default to utf-8 if Encoding.default_internal is nil" do
|
295
|
+
Encoding.default_internal = nil
|
296
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
297
|
+
result[field].encoding.should eql(Encoding.find('utf-8'))
|
298
|
+
|
299
|
+
client2 = Mysql2::Client.new :encoding => 'ascii'
|
300
|
+
client2.query "USE test"
|
301
|
+
result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
302
|
+
result[field].encoding.should eql(Encoding.find('us-ascii'))
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should use Encoding.default_internal" do
|
306
|
+
Encoding.default_internal = Encoding.find('utf-8')
|
307
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
308
|
+
result[field].encoding.should eql(Encoding.default_internal)
|
309
|
+
Encoding.default_internal = Encoding.find('us-ascii')
|
310
|
+
result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
311
|
+
result[field].encoding.should eql(Encoding.default_internal)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|