mysql2 0.2.18 → 0.2.19b1

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.
@@ -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'))