mysql2 0.2.6-x86-mingw32 → 0.2.16-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.
@@ -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.16"
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