mysql2 0.2.6-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +12 -0
  2. data/.rspec +2 -0
  3. data/CHANGELOG.md +117 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.rdoc +240 -0
  6. data/Rakefile +5 -0
  7. data/VERSION +1 -0
  8. data/benchmark/active_record.rb +53 -0
  9. data/benchmark/allocations.rb +33 -0
  10. data/benchmark/escape.rb +39 -0
  11. data/benchmark/query_with_mysql_casting.rb +83 -0
  12. data/benchmark/query_without_mysql_casting.rb +50 -0
  13. data/benchmark/sequel.rb +39 -0
  14. data/benchmark/setup_db.rb +115 -0
  15. data/examples/eventmachine.rb +21 -0
  16. data/examples/threaded.rb +20 -0
  17. data/ext/mysql2/client.c +659 -0
  18. data/ext/mysql2/client.h +41 -0
  19. data/ext/mysql2/extconf.rb +65 -0
  20. data/ext/mysql2/mysql2_ext.c +12 -0
  21. data/ext/mysql2/mysql2_ext.h +32 -0
  22. data/ext/mysql2/result.c +475 -0
  23. data/ext/mysql2/result.h +20 -0
  24. data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +63 -0
  25. data/lib/active_record/connection_adapters/mysql2_adapter.rb +654 -0
  26. data/lib/active_record/fiber_patches.rb +104 -0
  27. data/lib/arel/engines/sql/compilers/mysql2_compiler.rb +11 -0
  28. data/lib/mysql2.rb +16 -0
  29. data/lib/mysql2/client.rb +235 -0
  30. data/lib/mysql2/em.rb +33 -0
  31. data/lib/mysql2/error.rb +15 -0
  32. data/lib/mysql2/result.rb +5 -0
  33. data/mysql2.gemspec +89 -0
  34. data/spec/em/em_spec.rb +49 -0
  35. data/spec/mysql2/client_spec.rb +348 -0
  36. data/spec/mysql2/error_spec.rb +25 -0
  37. data/spec/mysql2/result_spec.rb +318 -0
  38. data/spec/rcov.opts +3 -0
  39. data/spec/spec_helper.rb +67 -0
  40. data/tasks/benchmarks.rake +8 -0
  41. data/tasks/compile.rake +54 -0
  42. data/tasks/jeweler.rake +17 -0
  43. data/tasks/rspec.rake +16 -0
  44. data/tasks/vendor_mysql.rake +41 -0
  45. metadata +120 -0
@@ -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