mysql2 0.2.18 → 0.2.19b1

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,18 +15,28 @@ module Mysql2
15
15
  def notify_readable
16
16
  detach
17
17
  begin
18
- @deferable.succeed(@client.async_result)
18
+ result = @client.async_result
19
19
  rescue Exception => e
20
20
  @deferable.fail(e)
21
+ else
22
+ @deferable.succeed(result)
21
23
  end
22
24
  end
23
25
  end
24
26
 
27
+ def close(*args)
28
+ if @watch
29
+ @watch.detach
30
+ end
31
+ super(*args)
32
+ end
33
+
25
34
  def query(sql, opts={})
26
35
  if ::EM.reactor_running?
27
36
  super(sql, opts.merge(:async => true))
28
37
  deferable = ::EM::DefaultDeferrable.new
29
- ::EM.watch(self.socket, Watcher, self, deferable).notify_readable = true
38
+ @watch = ::EM.watch(self.socket, Watcher, self, deferable)
39
+ @watch.notify_readable = true
30
40
  deferable
31
41
  else
32
42
  super(sql, opts)
@@ -34,4 +44,4 @@ module Mysql2
34
44
  end
35
45
  end
36
46
  end
37
- end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module Mysql2
2
- VERSION = "0.2.18"
2
+ VERSION = "0.2.19b1"
3
3
  end
@@ -0,0 +1,11 @@
1
+ root:
2
+ host: localhost
3
+ username: root
4
+ password:
5
+ database: test
6
+
7
+ user:
8
+ host: localhost
9
+ username: LOCALUSERNAME
10
+ password:
11
+ database: mysql2_test
@@ -8,7 +8,7 @@ if defined? EventMachine && defined? Fiber
8
8
  results = []
9
9
  EM.run do
10
10
  Fiber.new {
11
- client1 = Mysql2::EM::Fiber::Client.new
11
+ client1 = Mysql2::EM::Fiber::Client.new DatabaseCredentials['root']
12
12
  results = client1.query "SELECT sleep(0.1) as first_query"
13
13
  EM.stop_event_loop
14
14
  }.resume
@@ -19,4 +19,4 @@ if defined? EventMachine && defined? Fiber
19
19
  end
20
20
  else
21
21
  puts "Either EventMachine or Fibers not available. Skipping tests that use them."
22
- end
22
+ end
@@ -1,20 +1,21 @@
1
1
  # encoding: UTF-8
2
- if defined? EventMachine
3
- require 'spec_helper'
2
+ require 'spec_helper'
3
+ begin
4
+ require 'eventmachine'
4
5
  require 'mysql2/em'
5
6
 
6
7
  describe Mysql2::EM::Client do
7
8
  it "should support async queries" do
8
9
  results = []
9
10
  EM.run do
10
- client1 = Mysql2::EM::Client.new
11
+ client1 = Mysql2::EM::Client.new DatabaseCredentials['root']
11
12
  defer1 = client1.query "SELECT sleep(0.1) as first_query"
12
13
  defer1.callback do |result|
13
14
  results << result.first
14
15
  EM.stop_event_loop
15
16
  end
16
17
 
17
- client2 = Mysql2::EM::Client.new
18
+ client2 = Mysql2::EM::Client.new DatabaseCredentials['root']
18
19
  defer2 = client2.query "SELECT sleep(0.025) second_query"
19
20
  defer2.callback do |result|
20
21
  results << result.first
@@ -28,7 +29,7 @@ if defined? EventMachine
28
29
  it "should support queries in callbacks" do
29
30
  results = []
30
31
  EM.run do
31
- client = Mysql2::EM::Client.new
32
+ client = Mysql2::EM::Client.new DatabaseCredentials['root']
32
33
  defer1 = client.query "SELECT sleep(0.025) as first_query"
33
34
  defer1.callback do |result|
34
35
  results << result.first
@@ -43,7 +44,67 @@ if defined? EventMachine
43
44
  results[0].keys.should include("first_query")
44
45
  results[1].keys.should include("second_query")
45
46
  end
47
+
48
+ it "should not swallow exceptions raised in callbacks" do
49
+ lambda {
50
+ EM.run do
51
+ client = Mysql2::EM::Client.new DatabaseCredentials['root']
52
+ defer = client.query "SELECT sleep(0.1) as first_query"
53
+ defer.callback do |result|
54
+ raise 'some error'
55
+ end
56
+ defer.errback do |err|
57
+ # This _shouldn't_ be run, but it needed to prevent the specs from
58
+ # freezing if this test fails.
59
+ EM.stop_event_loop
60
+ end
61
+ end
62
+ }.should raise_error
63
+ end
64
+
65
+ context 'when an exception is raised by the client' do
66
+ let(:client) { Mysql2::EM::Client.new DatabaseCredentials['root'] }
67
+ let(:error) { StandardError.new('some error') }
68
+ before { client.stub(:async_result).and_raise(error) }
69
+
70
+ it "should swallow exceptions raised in by the client" do
71
+ errors = []
72
+ EM.run do
73
+ defer = client.query "SELECT sleep(0.1) as first_query"
74
+ defer.callback do |result|
75
+ # This _shouldn't_ be run, but it is needed to prevent the specs from
76
+ # freezing if this test fails.
77
+ EM.stop_event_loop
78
+ end
79
+ defer.errback do |err|
80
+ errors << err
81
+ EM.stop_event_loop
82
+ end
83
+ end
84
+ errors.should == [error]
85
+ end
86
+
87
+ it "should fail the deferrable" do
88
+ callbacks_run = []
89
+ EM.run do
90
+ defer = client.query "SELECT sleep(0.025) as first_query"
91
+ EM.add_timer(0.1) do
92
+ defer.callback do |result|
93
+ callbacks_run << :callback
94
+ # This _shouldn't_ be run, but it is needed to prevent the specs from
95
+ # freezing if this test fails.
96
+ EM.stop_event_loop
97
+ end
98
+ defer.errback do |err|
99
+ callbacks_run << :errback
100
+ EM.stop_event_loop
101
+ end
102
+ end
103
+ end
104
+ callbacks_run.should == [:errback]
105
+ end
106
+ end
46
107
  end
47
- else
108
+ rescue LoadError
48
109
  puts "EventMachine not installed, skipping the specs that use it"
49
- end
110
+ end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
 
4
4
  describe Mysql2::Client do
5
5
  before(:each) do
6
- @client = Mysql2::Client.new
6
+ @client = Mysql2::Client.new DatabaseCredentials['root']
7
7
  end
8
8
 
9
9
  if defined? Encoding
@@ -92,6 +92,22 @@ describe Mysql2::Client do
92
92
  end
93
93
 
94
94
  context "#query" do
95
+ it "should let you query again if iterating is finished when streaming" do
96
+ @client.query("SELECT 1 UNION SELECT 2", :stream => true, :cache_rows => false).each {}
97
+
98
+ expect {
99
+ @client.query("SELECT 1 UNION SELECT 2", :stream => true, :cache_rows => false)
100
+ }.to_not raise_exception(Mysql2::Error)
101
+ end
102
+
103
+ it "should not let you query again if iterating is not finished when streaming" do
104
+ @client.query("SELECT 1 UNION SELECT 2", :stream => true, :cache_rows => false).first
105
+
106
+ expect {
107
+ @client.query("SELECT 1 UNION SELECT 2", :stream => true, :cache_rows => false)
108
+ }.to raise_exception(Mysql2::Error)
109
+ end
110
+
95
111
  it "should only accept strings as the query parameter" do
96
112
  lambda {
97
113
  @client.query ["SELECT 'not right'"]
@@ -131,8 +147,21 @@ describe Mysql2::Client do
131
147
  }.should raise_error(Mysql2::Error)
132
148
  end
133
149
 
150
+ it "should describe the thread holding the active query" do
151
+ thr = Thread.new { @client.query("SELECT 1", :async => true) }
152
+
153
+ thr.join
154
+ begin
155
+ @client.query("SELECT 1")
156
+ rescue Mysql2::Error => e
157
+ message = e.message
158
+ end
159
+ re = Regexp.escape(thr.inspect)
160
+ message.should match(Regexp.new(re))
161
+ end
162
+
134
163
  it "should timeout if we wait longer than :read_timeout" do
135
- client = Mysql2::Client.new(:read_timeout => 1)
164
+ client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:read_timeout => 1))
136
165
  lambda {
137
166
  client.query("SELECT sleep(2)")
138
167
  }.should raise_error(Mysql2::Error)
@@ -184,14 +213,14 @@ describe Mysql2::Client do
184
213
  end
185
214
  rescue Timeout::Error
186
215
  end
187
-
216
+
188
217
  lambda {
189
218
  @client.query("SELECT 1")
190
219
  }.should raise_error(Mysql2::Error, 'closed MySQL connection')
191
220
  end
192
221
 
193
222
  it "should handle Timeouts without leaving the connection hanging if reconnect is true" do
194
- client = Mysql2::Client.new(:reconnect => true)
223
+ client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:reconnect => true))
195
224
  begin
196
225
  Timeout.timeout(1) do
197
226
  client.query("SELECT sleep(2)")
@@ -206,7 +235,9 @@ describe Mysql2::Client do
206
235
 
207
236
  it "threaded queries should be supported" do
208
237
  threads, results = [], {}
209
- connect = lambda{ Mysql2::Client.new(:host => "localhost", :username => "root") }
238
+ connect = lambda{
239
+ Mysql2::Client.new(DatabaseCredentials['root'])
240
+ }
210
241
  Timeout.timeout(0.7) do
211
242
  5.times {
212
243
  threads << Thread.new do
@@ -238,6 +269,38 @@ describe Mysql2::Client do
238
269
  result = @client.async_result
239
270
  result.class.should eql(Mysql2::Result)
240
271
  end
272
+
273
+ it "should not allow options to be set on an open connection" do
274
+ lambda {
275
+ @client.escape ""
276
+ @client.query("SELECT 1")
277
+ @client.options(0, 0)
278
+ }.should raise_error(Mysql2::Error)
279
+ end
280
+ end
281
+
282
+ context "Multiple results sets" do
283
+ before(:each) do
284
+ @multi_client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:flags => Mysql2::Client::MULTI_STATEMENTS))
285
+ end
286
+
287
+ it "returns multiple result sets" do
288
+ @multi_client.query( "select 1 as 'set_1'; select 2 as 'set_2'").first.should == { 'set_1' => 1 }
289
+
290
+ @multi_client.next_result.should == true
291
+ @multi_client.store_result.first.should == { 'set_2' => 2 }
292
+
293
+ @multi_client.next_result.should == false
294
+ end
295
+
296
+ it "does not interfere with other statements" do
297
+ @multi_client.query( "select 1 as 'set_1'; select 2 as 'set_2'")
298
+ while( @multi_client.next_result )
299
+ @multi_client.store_result
300
+ end
301
+
302
+ @multi_client.query( "select 3 as 'next'").first.should == { 'next' => 3 }
303
+ end
241
304
  end
242
305
  end
243
306
 
@@ -345,7 +408,7 @@ describe Mysql2::Client do
345
408
  Encoding.default_internal = nil
346
409
  @client.info[:version].encoding.should eql(Encoding.find('utf-8'))
347
410
 
348
- client2 = Mysql2::Client.new :encoding => 'ascii'
411
+ client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii'))
349
412
  client2.info[:version].encoding.should eql(Encoding.find('us-ascii'))
350
413
  end
351
414
 
@@ -384,7 +447,7 @@ describe Mysql2::Client do
384
447
  Encoding.default_internal = nil
385
448
  @client.server_info[:version].encoding.should eql(Encoding.find('utf-8'))
386
449
 
387
- client2 = Mysql2::Client.new :encoding => 'ascii'
450
+ client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii'))
388
451
  client2.server_info[:version].encoding.should eql(Encoding.find('us-ascii'))
389
452
  end
390
453
 
@@ -403,7 +466,7 @@ describe Mysql2::Client do
403
466
  }.should raise_error(Mysql2::Error)
404
467
 
405
468
  lambda {
406
- good_client = Mysql2::Client.new
469
+ good_client = Mysql2::Client.new DatabaseCredentials['root']
407
470
  }.should_not raise_error(Mysql2::Error)
408
471
  end
409
472
 
@@ -451,15 +514,54 @@ describe Mysql2::Client do
451
514
  @client.should respond_to(:ping)
452
515
  end
453
516
 
517
+ context "select_db" do
518
+ before(:each) do
519
+ 2.times do |i|
520
+ @client.query("CREATE DATABASE test_selectdb_#{i}")
521
+ @client.query("USE test_selectdb_#{i}")
522
+ @client.query("CREATE TABLE test#{i} (`id` int NOT NULL PRIMARY KEY)")
523
+ end
524
+ end
525
+
526
+ after(:each) do
527
+ 2.times do |i|
528
+ @client.query("DROP DATABASE test_selectdb_#{i}")
529
+ end
530
+ end
531
+
532
+ it "should respond to #select_db" do
533
+ @client.should respond_to(:select_db)
534
+ end
535
+
536
+ it "should switch databases" do
537
+ @client.select_db("test_selectdb_0")
538
+ @client.query("SHOW TABLES").first.values.first.should eql("test0")
539
+ @client.select_db("test_selectdb_1")
540
+ @client.query("SHOW TABLES").first.values.first.should eql("test1")
541
+ @client.select_db("test_selectdb_0")
542
+ @client.query("SHOW TABLES").first.values.first.should eql("test0")
543
+ end
544
+
545
+ it "should raise a Mysql2::Error when the database doesn't exist" do
546
+ lambda {
547
+ @client.select_db("nopenothere")
548
+ }.should raise_error(Mysql2::Error)
549
+ end
550
+
551
+ it "should return the database switched to" do
552
+ @client.select_db("test_selectdb_1").should eq("test_selectdb_1")
553
+ end
554
+ end
555
+
454
556
  it "#thread_id should return a boolean" do
455
557
  @client.ping.should eql(true)
456
558
  @client.close
457
559
  @client.ping.should eql(false)
458
560
  end
459
561
 
460
- if RUBY_VERSION =~ /1.9/
461
- it "should respond to #encoding" do
462
- @client.should respond_to(:encoding)
562
+ if RUBY_VERSION =~ /1.9/
563
+ it "should respond to #encoding" do
564
+ @client.should respond_to(:encoding)
565
+ end
463
566
  end
464
567
  end
465
- end
@@ -3,14 +3,14 @@ require 'spec_helper'
3
3
 
4
4
  describe Mysql2::Error do
5
5
  before(:each) do
6
- @client = Mysql2::Client.new :encoding => "utf8"
6
+ @client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "utf8"))
7
7
  begin
8
8
  @client.query("HAHAHA")
9
9
  rescue Mysql2::Error => e
10
10
  @error = e
11
11
  end
12
12
 
13
- @client2 = Mysql2::Client.new :encoding => "big5"
13
+ @client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "big5"))
14
14
  begin
15
15
  @client2.query("HAHAHA")
16
16
  rescue Mysql2::Error => e
@@ -3,13 +3,42 @@ require 'spec_helper'
3
3
 
4
4
  describe Mysql2::Result do
5
5
  before(:each) do
6
- @client = Mysql2::Client.new :host => "localhost", :username => "root", :database => 'test'
6
+ @client = Mysql2::Client.new DatabaseCredentials['root']
7
7
  end
8
8
 
9
9
  before(:each) do
10
10
  @result = @client.query "SELECT 1"
11
11
  end
12
12
 
13
+ it "should maintain a count while streaming" do
14
+ result = @client.query('SELECT 1')
15
+
16
+ result.count.should eql(1)
17
+ result.each { |r| }
18
+ result.count.should eql(1)
19
+ end
20
+
21
+ it "should set the actual count of rows after streaming" do
22
+ @client.query "USE test"
23
+ result = @client.query("SELECT * FROM mysql2_test", :stream => true, :cache_rows => false)
24
+ result.count.should eql(0)
25
+ result.each {|r| }
26
+ result.count.should eql(1)
27
+ end
28
+
29
+ it "should not yield nil at the end of streaming" do
30
+ result = @client.query('SELECT * FROM mysql2_test', :stream => true)
31
+ result.each { |r| r.should_not be_nil}
32
+ end
33
+
34
+ it "#count should be zero for rows after streaming when there were no results " do
35
+ @client.query "USE test"
36
+ result = @client.query("SELECT * FROM mysql2_test WHERE null_test IS NOT NULL", :stream => true, :cache_rows => false)
37
+ result.count.should eql(0)
38
+ result.each {|r| }
39
+ result.count.should eql(0)
40
+ end
41
+
13
42
  it "should have included Enumerable" do
14
43
  Mysql2::Result.ancestors.include?(Enumerable).should be_true
15
44
  end
@@ -73,6 +102,25 @@ describe Mysql2::Result do
73
102
  result = @client.query "SELECT 1", :cache_rows => false
74
103
  result.first.object_id.should_not eql(result.first.object_id)
75
104
  end
105
+
106
+ it "should yield different value for #first if streaming" do
107
+ result = @client.query "SELECT 1 UNION SELECT 2", :stream => true, :cache_rows => false
108
+ result.first.should_not eql(result.first)
109
+ end
110
+
111
+ it "should yield the same value for #first if streaming is disabled" do
112
+ result = @client.query "SELECT 1 UNION SELECT 2", :stream => false
113
+ result.first.should eql(result.first)
114
+ end
115
+
116
+ it "should throw an exception if we try to iterate twice when streaming is enabled" do
117
+ result = @client.query "SELECT 1 UNION SELECT 2", :stream => true, :cache_rows => false
118
+
119
+ expect {
120
+ result.each {}
121
+ result.each {}
122
+ }.to raise_exception(Mysql2::Error)
123
+ end
76
124
  end
77
125
 
78
126
  context "#fields" do
@@ -127,13 +175,17 @@ describe Mysql2::Result do
127
175
  id1 = @client.last_id
128
176
  @client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (0)'
129
177
  id2 = @client.last_id
178
+ @client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (-1)'
179
+ id3 = @client.last_id
130
180
 
131
181
  result1 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = 1 LIMIT 1', :cast_booleans => true
132
182
  result2 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = 0 LIMIT 1', :cast_booleans => true
183
+ result3 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = -1 LIMIT 1', :cast_booleans => true
133
184
  result1.first['bool_cast_test'].should be_true
134
185
  result2.first['bool_cast_test'].should be_false
186
+ result3.first['bool_cast_test'].should be_true
135
187
 
136
- @client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2})"
188
+ @client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2},#{id3})"
137
189
  end
138
190
 
139
191
  it "should return Fixnum for a SMALLINT value" do
@@ -255,7 +307,7 @@ describe Mysql2::Result do
255
307
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
256
308
  result['enum_test'].encoding.should eql(Encoding.find('utf-8'))
257
309
 
258
- client2 = Mysql2::Client.new :encoding => 'ascii'
310
+ client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii'))
259
311
  client2.query "USE test"
260
312
  result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
261
313
  result['enum_test'].encoding.should eql(Encoding.find('us-ascii'))
@@ -284,7 +336,7 @@ describe Mysql2::Result do
284
336
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
285
337
  result['set_test'].encoding.should eql(Encoding.find('utf-8'))
286
338
 
287
- client2 = Mysql2::Client.new :encoding => 'ascii'
339
+ client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii'))
288
340
  client2.query "USE test"
289
341
  result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
290
342
  result['set_test'].encoding.should eql(Encoding.find('us-ascii'))
@@ -366,7 +418,7 @@ describe Mysql2::Result do
366
418
  result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
367
419
  result[field].encoding.should eql(Encoding.find('utf-8'))
368
420
 
369
- client2 = Mysql2::Client.new :encoding => 'ascii'
421
+ client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii'))
370
422
  client2.query "USE test"
371
423
  result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
372
424
  result[field].encoding.should eql(Encoding.find('us-ascii'))