mysql2 0.2.6-x86-mswin32-60 → 0.2.15-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,7 +24,7 @@ module ActiveRecord
24
24
  fiber.resume(false)
25
25
  end
26
26
  @queue << fiber
27
- returning Fiber.yield do
27
+ Fiber.yield.tap do
28
28
  x.cancel
29
29
  end
30
30
  end
@@ -67,16 +67,38 @@ module ActiveRecord
67
67
 
68
68
  @connections = []
69
69
  @checked_out = []
70
- end
70
+ @automatic_reconnect = true
71
+ @tables = {}
71
72
 
72
- private
73
+ @columns = Hash.new do |h, table_name|
74
+ h[table_name] = with_connection do |conn|
73
75
 
74
- def current_connection_id #:nodoc:
75
- Fiber.current.object_id
76
+ # Fetch a list of columns
77
+ conn.columns(table_name, "#{table_name} Columns").tap do |columns|
78
+
79
+ # set primary key information
80
+ columns.each do |column|
81
+ column.primary = column.name == primary_keys[table_name]
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ @columns_hash = Hash.new do |h, table_name|
88
+ h[table_name] = Hash[columns[table_name].map { |col|
89
+ [col.name, col]
90
+ }]
91
+ end
92
+
93
+ @primary_keys = Hash.new do |h, table_name|
94
+ h[table_name] = with_connection do |conn|
95
+ table_exists?(table_name) ? conn.primary_key(table_name) : 'id'
96
+ end
97
+ end
76
98
  end
77
99
 
78
- # Remove stale fibers from the cache.
79
- def remove_stale_cached_threads!(cache, &block)
100
+ def clear_stale_cached_connections!
101
+ cache = @reserved_connections
80
102
  keys = Set.new(cache.keys)
81
103
 
82
104
  ActiveRecord::ConnectionAdapters.fiber_pools.each do |pool|
@@ -87,11 +109,17 @@ module ActiveRecord
87
109
 
88
110
  keys.each do |key|
89
111
  next unless cache.has_key?(key)
90
- block.call(key, cache[key])
112
+ checkin cache[key]
91
113
  cache.delete(key)
92
114
  end
93
115
  end
94
116
 
117
+ private
118
+
119
+ def current_connection_id #:nodoc:
120
+ Fiber.current.object_id
121
+ end
122
+
95
123
  def checkout_and_verify(c)
96
124
  @checked_out << c
97
125
  c.run_callbacks :checkout
@@ -101,4 +129,4 @@ module ActiveRecord
101
129
  end
102
130
 
103
131
  end
104
- end
132
+ end
@@ -3,14 +3,19 @@ require 'date'
3
3
  require 'bigdecimal'
4
4
  require 'rational' unless RUBY_VERSION >= '1.9.2'
5
5
 
6
+ require 'mysql2/version' unless defined? Mysql2::VERSION
6
7
  require 'mysql2/error'
8
+ require 'mysql2/result'
7
9
  require 'mysql2/mysql2'
8
10
  require 'mysql2/client'
9
- require 'mysql2/result'
10
11
 
11
12
  # = Mysql2
12
13
  #
13
14
  # A modern, simple and very fast Mysql library for Ruby - binding to libmysql
14
15
  module Mysql2
15
- VERSION = "0.2.6"
16
16
  end
17
+
18
+ if defined?(ActiveRecord::VERSION::STRING) && ActiveRecord::VERSION::STRING >= "3.1"
19
+ puts "WARNING: This version of mysql2 (#{Mysql2::VERSION}) isn't compatible with Rails 3.1 as the ActiveRecord adapter was pulled into Rails itself."
20
+ puts "WARNING: Please use the 0.3.x (or greater) releases if you plan on using it in Rails >= 3.1.x"
21
+ end
@@ -9,11 +9,13 @@ module Mysql2
9
9
  :database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in
10
10
  :application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller
11
11
  :cache_rows => true, # tells Mysql2 to use it's internal row cache for results
12
- :connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION
12
+ :connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION,
13
+ :cast => true
13
14
  }
14
15
 
15
16
  def initialize(opts = {})
16
17
  @query_options = @@default_query_options.dup
18
+ @query_options.merge! opts
17
19
 
18
20
  init_connection
19
21
 
@@ -24,7 +26,12 @@ module Mysql2
24
26
  # force the encoding to utf8
25
27
  self.charset_name = opts[:encoding] || 'utf8'
26
28
 
27
- ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslciper))
29
+ @read_timeout = opts[:read_timeout]
30
+ if @read_timeout and @read_timeout < 0
31
+ raise Mysql2::Error, "read_timeout must be a positive integer, you passed #{@read_timeout}"
32
+ end
33
+
34
+ ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher))
28
35
 
29
36
  user = opts[:username]
30
37
  pass = opts[:password]
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'eventmachine' unless defined? EventMachine
4
- require 'mysql2' unless defined? Mysql2
3
+ require 'eventmachine'
4
+ require 'mysql2'
5
5
 
6
6
  module Mysql2
7
7
  module EM
@@ -23,10 +23,14 @@ module Mysql2
23
23
  end
24
24
 
25
25
  def query(sql, opts={})
26
- super(sql, opts.merge(:async => true))
27
- deferable = ::EM::DefaultDeferrable.new
28
- ::EM.watch(self.socket, Watcher, self, deferable).notify_readable = true
29
- deferable
26
+ if ::EM.reactor_running?
27
+ super(sql, opts.merge(:async => true))
28
+ deferable = ::EM::DefaultDeferrable.new
29
+ ::EM.watch(self.socket, Watcher, self, deferable).notify_readable = true
30
+ deferable
31
+ else
32
+ super(sql, opts)
33
+ end
30
34
  end
31
35
  end
32
36
  end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ require 'mysql2/em'
4
+ require 'fiber'
5
+
6
+ module Mysql2
7
+ module EM
8
+ module Fiber
9
+ class Client < ::Mysql2::EM::Client
10
+ def query(sql, opts={})
11
+ if ::EM.reactor_running?
12
+ deferable = super(sql, opts)
13
+
14
+ fiber = ::Fiber.current
15
+ deferable.callback do |result|
16
+ fiber.resume(result)
17
+ end
18
+ deferable.errback do |err|
19
+ fiber.resume(err)
20
+ end
21
+ ::Fiber.yield.tap do |result|
22
+ raise result if result.is_a?(::Exception)
23
+ end
24
+ else
25
+ super(sql, opts)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module Mysql2
2
+ VERSION = "0.2.15"
3
+ end
@@ -1,89 +1,29 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
1
+ require File.expand_path('../lib/mysql2/version', __FILE__)
5
2
 
6
3
  Gem::Specification.new do |s|
7
4
  s.name = %q{mysql2}
8
- s.version = "0.2.6"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
5
+ s.version = Mysql2::VERSION
11
6
  s.authors = ["Brian Lopez"]
12
- s.date = %q{2010-10-19}
7
+ s.date = Time.now.utc.strftime("%Y-%m-%d")
13
8
  s.email = %q{seniorlopez@gmail.com}
14
9
  s.extensions = ["ext/mysql2/extconf.rb"]
15
- s.extra_rdoc_files = [
16
- "README.rdoc"
17
- ]
18
- s.files = [
19
- ".gitignore",
20
- ".rspec",
21
- "CHANGELOG.md",
22
- "MIT-LICENSE",
23
- "README.rdoc",
24
- "Rakefile",
25
- "VERSION",
26
- "benchmark/active_record.rb",
27
- "benchmark/allocations.rb",
28
- "benchmark/escape.rb",
29
- "benchmark/query_with_mysql_casting.rb",
30
- "benchmark/query_without_mysql_casting.rb",
31
- "benchmark/sequel.rb",
32
- "benchmark/setup_db.rb",
33
- "examples/eventmachine.rb",
34
- "examples/threaded.rb",
35
- "ext/mysql2/client.c",
36
- "ext/mysql2/client.h",
37
- "ext/mysql2/extconf.rb",
38
- "ext/mysql2/mysql2_ext.c",
39
- "ext/mysql2/mysql2_ext.h",
40
- "ext/mysql2/result.c",
41
- "ext/mysql2/result.h",
42
- "lib/active_record/connection_adapters/em_mysql2_adapter.rb",
43
- "lib/active_record/connection_adapters/mysql2_adapter.rb",
44
- "lib/active_record/fiber_patches.rb",
45
- "lib/arel/engines/sql/compilers/mysql2_compiler.rb",
46
- "lib/mysql2.rb",
47
- "lib/mysql2/client.rb",
48
- "lib/mysql2/em.rb",
49
- "lib/mysql2/error.rb",
50
- "lib/mysql2/result.rb",
51
- "mysql2.gemspec",
52
- "spec/em/em_spec.rb",
53
- "spec/mysql2/client_spec.rb",
54
- "spec/mysql2/error_spec.rb",
55
- "spec/mysql2/result_spec.rb",
56
- "spec/rcov.opts",
57
- "spec/spec_helper.rb",
58
- "tasks/benchmarks.rake",
59
- "tasks/compile.rake",
60
- "tasks/jeweler.rake",
61
- "tasks/rspec.rake",
62
- "tasks/vendor_mysql.rake"
63
- ]
10
+ s.files = `git ls-files`.split("\n")
64
11
  s.homepage = %q{http://github.com/brianmario/mysql2}
65
12
  s.rdoc_options = ["--charset=UTF-8"]
66
- s.require_paths = ["lib", "ext"]
67
- s.rubygems_version = %q{1.3.7}
13
+ s.require_paths = ["lib"]
14
+ s.rubygems_version = %q{1.4.2}
68
15
  s.summary = %q{A simple, fast Mysql library for Ruby, binding to libmysql}
69
- s.test_files = [
70
- "spec/em/em_spec.rb",
71
- "spec/mysql2/client_spec.rb",
72
- "spec/mysql2/error_spec.rb",
73
- "spec/mysql2/result_spec.rb",
74
- "spec/spec_helper.rb",
75
- "examples/eventmachine.rb",
76
- "examples/threaded.rb"
77
- ]
78
-
79
- if s.respond_to? :specification_version then
80
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
81
- s.specification_version = 3
16
+ s.test_files = `git ls-files spec examples`.split("\n")
82
17
 
83
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
84
- else
85
- end
86
- else
87
- end
18
+ # tests
19
+ s.add_development_dependency 'eventmachine'
20
+ s.add_development_dependency 'rake-compiler', "~> 0.7.7"
21
+ s.add_development_dependency 'rake', '0.8.7' # NB: 0.8.7 required by rake-compiler 0.7.9
22
+ s.add_development_dependency 'rspec'
23
+ # benchmarks
24
+ s.add_development_dependency 'activerecord'
25
+ s.add_development_dependency 'mysql'
26
+ s.add_development_dependency 'do_mysql'
27
+ s.add_development_dependency 'sequel'
28
+ s.add_development_dependency 'faker'
88
29
  end
89
-
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+ if defined? EventMachine && defined? Fiber
3
+ require 'spec_helper'
4
+ require 'mysql2/em_fiber'
5
+
6
+ describe Mysql2::EM::Fiber::Client do
7
+ it 'should support queries' do
8
+ results = []
9
+ EM.run do
10
+ Fiber.new {
11
+ client1 = Mysql2::EM::Fiber::Client.new
12
+ results = client1.query "SELECT sleep(0.1) as first_query"
13
+ EM.stop_event_loop
14
+ }.resume
15
+ end
16
+
17
+ results.first.keys.should include("first_query")
18
+ end
19
+ end
20
+ else
21
+ puts "Either EventMachine or Fibers not available. Skipping tests that use them."
22
+ end
@@ -85,7 +85,19 @@ describe Mysql2::Client do
85
85
  @client.should respond_to(:query)
86
86
  end
87
87
 
88
+ it "should expect read_timeout to be a positive integer" do
89
+ lambda {
90
+ Mysql2::Client.new(:read_timeout => -1)
91
+ }.should raise_error(Mysql2::Error)
92
+ end
93
+
88
94
  context "#query" do
95
+ it "should only accept strings as the query parameter" do
96
+ lambda {
97
+ @client.query ["SELECT 'not right'"]
98
+ }.should raise_error(TypeError)
99
+ end
100
+
89
101
  it "should accept an options hash that inherits from Mysql2::Client.default_query_options" do
90
102
  @client.query "SELECT 1", :something => :else
91
103
  @client.query_options.should eql(@client.query_options.merge(:something => :else))
@@ -104,13 +116,6 @@ describe Mysql2::Client do
104
116
  @client.query("SELECT 1", :symbolize_keys => true).first.keys[0].class.should eql(Symbol)
105
117
  end
106
118
 
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
119
  it "should require an open connection" do
115
120
  @client.close
116
121
  lambda {
@@ -118,9 +123,23 @@ describe Mysql2::Client do
118
123
  }.should raise_error(Mysql2::Error)
119
124
  end
120
125
 
121
- # XXX this test is not deterministic (because Unix signal handling is not)
122
- # and may fail on a loaded system
123
126
  if RUBY_PLATFORM !~ /mingw|mswin/
127
+ it "should not allow another query to be sent without fetching a result first" do
128
+ @client.query("SELECT 1", :async => true)
129
+ lambda {
130
+ @client.query("SELECT 1")
131
+ }.should raise_error(Mysql2::Error)
132
+ end
133
+
134
+ it "should timeout if we wait longer than :read_timeout" do
135
+ client = Mysql2::Client.new(:read_timeout => 1)
136
+ lambda {
137
+ client.query("SELECT sleep(2)")
138
+ }.should raise_error(Mysql2::Error)
139
+ end
140
+
141
+ # XXX this test is not deterministic (because Unix signal handling is not)
142
+ # and may fail on a loaded system
124
143
  it "should run signal handlers while waiting for a response" do
125
144
  mark = {}
126
145
  trap(:USR1) { mark[:USR1] = Time.now }
@@ -145,6 +164,131 @@ describe Mysql2::Client do
145
164
  trap(:USR1, 'DEFAULT')
146
165
  end
147
166
  end
167
+
168
+ it "#socket should return a Fixnum (file descriptor from C)" do
169
+ @client.socket.class.should eql(Fixnum)
170
+ @client.socket.should_not eql(0)
171
+ end
172
+
173
+ it "#socket should require an open connection" do
174
+ @client.close
175
+ lambda {
176
+ @client.socket
177
+ }.should raise_error(Mysql2::Error)
178
+ end
179
+
180
+ it "should close the connection when an exception is raised" do
181
+ begin
182
+ Timeout.timeout(1) do
183
+ @client.query("SELECT sleep(2)")
184
+ end
185
+ rescue Timeout::Error
186
+ end
187
+
188
+ lambda {
189
+ @client.query("SELECT 1")
190
+ }.should raise_error(Mysql2::Error, 'closed MySQL connection')
191
+ end
192
+
193
+ it "should handle Timeouts without leaving the connection hanging if reconnect is true" do
194
+ client = Mysql2::Client.new(:reconnect => true)
195
+ begin
196
+ Timeout.timeout(1) do
197
+ client.query("SELECT sleep(2)")
198
+ end
199
+ rescue Timeout::Error
200
+ end
201
+
202
+ lambda {
203
+ client.query("SELECT 1")
204
+ }.should_not raise_error(Mysql2::Error)
205
+ end
206
+
207
+ it "threaded queries should be supported" do
208
+ threads, results = [], {}
209
+ connect = lambda{ Mysql2::Client.new(:host => "localhost", :username => "root") }
210
+ Timeout.timeout(0.7) do
211
+ 5.times {
212
+ threads << Thread.new do
213
+ results[Thread.current.object_id] = connect.call.query("SELECT sleep(0.5) as result")
214
+ end
215
+ }
216
+ end
217
+ threads.each{|t| t.join }
218
+ results.keys.sort.should eql(threads.map{|t| t.object_id }.sort)
219
+ end
220
+
221
+ it "evented async queries should be supported" do
222
+ # should immediately return nil
223
+ @client.query("SELECT sleep(0.1)", :async => true).should eql(nil)
224
+
225
+ io_wrapper = IO.for_fd(@client.socket)
226
+ loops = 0
227
+ loop do
228
+ if IO.select([io_wrapper], nil, nil, 0.05)
229
+ break
230
+ else
231
+ loops += 1
232
+ end
233
+ end
234
+
235
+ # make sure we waited some period of time
236
+ (loops >= 1).should be_true
237
+
238
+ result = @client.async_result
239
+ result.class.should eql(Mysql2::Result)
240
+ end
241
+ end
242
+ end
243
+
244
+ it "should respond to #socket" do
245
+ @client.should respond_to(:socket)
246
+ end
247
+
248
+ if RUBY_PLATFORM =~ /mingw|mswin/
249
+ it "#socket should raise as it's not supported" do
250
+ lambda {
251
+ @client.socket
252
+ }.should raise_error(Mysql2::Error)
253
+ end
254
+ end
255
+
256
+ it "should respond to escape" do
257
+ Mysql2::Client.should respond_to(:escape)
258
+ end
259
+
260
+ context "escape" do
261
+ it "should return a new SQL-escape version of the passed string" do
262
+ Mysql2::Client.escape("abc'def\"ghi\0jkl%mno").should eql("abc\\'def\\\"ghi\\0jkl%mno")
263
+ end
264
+
265
+ it "should return the passed string if nothing was escaped" do
266
+ str = "plain"
267
+ Mysql2::Client.escape(str).object_id.should eql(str.object_id)
268
+ end
269
+
270
+ it "should not overflow the thread stack" do
271
+ lambda {
272
+ Thread.new { Mysql2::Client.escape("'" * 256 * 1024) }.join
273
+ }.should_not raise_error(SystemStackError)
274
+ end
275
+
276
+ it "should not overflow the process stack" do
277
+ lambda {
278
+ Thread.new { Mysql2::Client.escape("'" * 1024 * 1024 * 4) }.join
279
+ }.should_not raise_error(SystemStackError)
280
+ end
281
+
282
+ if RUBY_VERSION =~ /1.9/
283
+ it "should carry over the original string's encoding" do
284
+ str = "abc'def\"ghi\0jkl%mno"
285
+ escaped = Mysql2::Client.escape(str)
286
+ escaped.encoding.should eql(str.encoding)
287
+
288
+ str.encode!('us-ascii')
289
+ escaped = Mysql2::Client.escape(str)
290
+ escaped.encoding.should eql(str.encoding)
291
+ end
148
292
  end
149
293
  end
150
294
 
@@ -253,25 +397,9 @@ describe Mysql2::Client do
253
397
  end
254
398
  end
255
399
 
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
400
  it "should raise a Mysql2::Error exception upon connection failure" do
273
401
  lambda {
274
- bad_client = Mysql2::Client.new :host => "dfjhdi9wrhw", :username => 'asdfasdf8d2h'
402
+ bad_client = Mysql2::Client.new :host => "localhost", :username => 'asdfasdf8d2h', :password => 'asdfasdfw42'
275
403
  }.should raise_error(Mysql2::Error)
276
404
 
277
405
  lambda {
@@ -279,45 +407,10 @@ describe Mysql2::Client do
279
407
  }.should_not raise_error(Mysql2::Error)
280
408
  end
281
409
 
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
410
  context 'write operations api' do
318
411
  before(:each) do
319
412
  @client.query "USE test"
320
- @client.query "CREATE TABLE lastIdTest (`id` int(11) NOT NULL AUTO_INCREMENT, blah INT(11), PRIMARY KEY (`id`))"
413
+ @client.query "CREATE TABLE IF NOT EXISTS lastIdTest (`id` int(11) NOT NULL AUTO_INCREMENT, blah INT(11), PRIMARY KEY (`id`))"
321
414
  end
322
415
 
323
416
  after(:each) do
@@ -345,4 +438,28 @@ describe Mysql2::Client do
345
438
  @client.affected_rows.should eql(1)
346
439
  end
347
440
  end
441
+
442
+ it "should respond to #thread_id" do
443
+ @client.should respond_to(:thread_id)
444
+ end
445
+
446
+ it "#thread_id should be a Fixnum" do
447
+ @client.thread_id.class.should eql(Fixnum)
448
+ end
449
+
450
+ it "should respond to #ping" do
451
+ @client.should respond_to(:ping)
452
+ end
453
+
454
+ it "#thread_id should return a boolean" do
455
+ @client.ping.should eql(true)
456
+ @client.close
457
+ @client.ping.should eql(false)
458
+ end
459
+
460
+ if RUBY_VERSION =~ /1.9/
461
+ it "should respond to #encoding" do
462
+ @client.should respond_to(:encoding)
463
+ end
464
+ end
348
465
  end