mysql2 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +5 -0
- data/README.rdoc +28 -0
- data/VERSION +1 -1
- data/benchmark/active_record.rb +39 -0
- data/benchmark/escape.rb +1 -4
- data/examples/eventmachine.rb +21 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +165 -0
- data/lib/arel/engines/sql/compilers/mysql2_compiler.rb +11 -0
- data/lib/mysql2.rb +1 -1
- data/lib/mysql2/em.rb +33 -0
- data/mysql2.gemspec +14 -4
- data/spec/active_record/active_record_spec.rb +23 -0
- data/spec/em/em_spec.rb +26 -0
- metadata +13 -3
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.1.3 (April 15th, 2010)
|
4
|
+
* added an EventMachine Deferrable API
|
5
|
+
* added an ActiveRecord connection adapter
|
6
|
+
** should be compatible with 2.3.5 and 3.0 (including Arel)
|
7
|
+
|
3
8
|
## 0.1.2 (April 9th, 2010)
|
4
9
|
* fix a bug (copy/paste fail) around checking for empty TIME values and returning nil (thanks @marius)
|
5
10
|
|
data/README.rdoc
CHANGED
@@ -75,6 +75,32 @@ NOTE: Because of the way MySQL's query API works, this method will block until t
|
|
75
75
|
So if you really need things to stay async, it's best to just monitor the socket with something like EventMachine.
|
76
76
|
If you need multiple query concurrency take a look at using a connection pool.
|
77
77
|
|
78
|
+
== ActiveRecord
|
79
|
+
|
80
|
+
To use the ActiveRecord driver, all you should need to do is have this gem installed and set the adapter in your database.yml to "mysql2".
|
81
|
+
That was easy right? :)
|
82
|
+
|
83
|
+
== EventMachine
|
84
|
+
|
85
|
+
The mysql2 EventMachine deferrable api allows you to make async queries using EventMachine,
|
86
|
+
while specifying callbacks for success for failure. Here's a simple example:
|
87
|
+
|
88
|
+
require 'mysql2/em'
|
89
|
+
|
90
|
+
EM.run do
|
91
|
+
client1 = Mysql2::EM::Client.new
|
92
|
+
defer1 = client1.query "SELECT sleep(3) as first_query"
|
93
|
+
defer1.callback do |result|
|
94
|
+
puts "Result: #{result.to_a.inspect}"
|
95
|
+
end
|
96
|
+
|
97
|
+
client2 = Mysql2::EM::Client.new
|
98
|
+
defer2 = client2.query "SELECT sleep(1) second_query"
|
99
|
+
defer2.callback do |result|
|
100
|
+
puts "Result: #{result.to_a.inspect}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
78
104
|
== Compatibility
|
79
105
|
|
80
106
|
The specs pass on my system (SL 10.6.3, x86_64) in these rubies:
|
@@ -85,6 +111,8 @@ The specs pass on my system (SL 10.6.3, x86_64) in these rubies:
|
|
85
111
|
* ruby-trunk
|
86
112
|
* rbx-head
|
87
113
|
|
114
|
+
The ActiveRecord driver should work on 2.3.5 and 3.0
|
115
|
+
|
88
116
|
== Yeah... but why?
|
89
117
|
|
90
118
|
Someone: Dude, the Mysql gem works fiiiiiine.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.3
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'benchmark'
|
6
|
+
require 'active_record'
|
7
|
+
require 'ruby-debug'
|
8
|
+
|
9
|
+
number_of = 1
|
10
|
+
mysql2_opts = {
|
11
|
+
:adapter => 'mysql2',
|
12
|
+
:database => 'test'
|
13
|
+
}
|
14
|
+
mysql_opts = {
|
15
|
+
:adapter => 'mysql',
|
16
|
+
:database => 'test'
|
17
|
+
}
|
18
|
+
|
19
|
+
class TestModel < ActiveRecord::Base
|
20
|
+
set_table_name :mysql2_test
|
21
|
+
end
|
22
|
+
|
23
|
+
Benchmark.bmbm do |x|
|
24
|
+
x.report do
|
25
|
+
TestModel.establish_connection(mysql2_opts)
|
26
|
+
puts "Mysql2"
|
27
|
+
number_of.times do
|
28
|
+
TestModel.all(:limit => 1000)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
x.report do
|
33
|
+
TestModel.establish_connection(mysql_opts)
|
34
|
+
puts "Mysql"
|
35
|
+
number_of.times do
|
36
|
+
TestModel.all(:limit => 1000)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/benchmark/escape.rb
CHANGED
@@ -7,12 +7,10 @@ require 'mysql2_ext'
|
|
7
7
|
require 'do_mysql'
|
8
8
|
|
9
9
|
number_of = 1000
|
10
|
-
database = 'nbb_1_production'
|
11
10
|
str = "abc'def\"ghi\0jkl%mno"
|
12
11
|
|
13
12
|
Benchmark.bmbm do |x|
|
14
13
|
mysql = Mysql.new("localhost", "root")
|
15
|
-
mysql.query "USE #{database}"
|
16
14
|
x.report do
|
17
15
|
puts "Mysql"
|
18
16
|
number_of.times do
|
@@ -21,7 +19,6 @@ Benchmark.bmbm do |x|
|
|
21
19
|
end
|
22
20
|
|
23
21
|
mysql2 = Mysql2::Client.new(:host => "localhost", :username => "root")
|
24
|
-
mysql2.query "USE #{database}"
|
25
22
|
x.report do
|
26
23
|
puts "Mysql2"
|
27
24
|
number_of.times do
|
@@ -29,7 +26,7 @@ Benchmark.bmbm do |x|
|
|
29
26
|
end
|
30
27
|
end
|
31
28
|
|
32
|
-
do_mysql = DataObjects::Connection.new("mysql://localhost
|
29
|
+
do_mysql = DataObjects::Connection.new("mysql://localhost/test")
|
33
30
|
x.report do
|
34
31
|
puts "do_mysql"
|
35
32
|
number_of.times do
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift 'lib'
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'eventmachine'
|
7
|
+
require 'mysql2/em'
|
8
|
+
|
9
|
+
EM.run do
|
10
|
+
client1 = Mysql2::EM::Client.new
|
11
|
+
defer1 = client1.query "SELECT sleep(3) as first_query"
|
12
|
+
defer1.callback do |result|
|
13
|
+
puts "Result: #{result.to_a.inspect}"
|
14
|
+
end
|
15
|
+
|
16
|
+
client2 = Mysql2::EM::Client.new
|
17
|
+
defer2 = client2.query "SELECT sleep(1) second_query"
|
18
|
+
defer2.callback do |result|
|
19
|
+
puts "Result: #{result.to_a.inspect}"
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'mysql2' unless defined? Mysql2
|
4
|
+
require 'active_record/connection_adapters/mysql_adapter'
|
5
|
+
|
6
|
+
module ActiveRecord
|
7
|
+
class Base
|
8
|
+
def self.mysql2_connection(config)
|
9
|
+
client = Mysql2::Client.new(config.symbolize_keys)
|
10
|
+
options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
|
11
|
+
ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ConnectionAdapters
|
16
|
+
class Mysql2Column < MysqlColumn
|
17
|
+
# Returns the Ruby class that corresponds to the abstract data type.
|
18
|
+
def klass
|
19
|
+
case type
|
20
|
+
when :integer then Fixnum
|
21
|
+
when :float then Float
|
22
|
+
when :decimal then BigDecimal
|
23
|
+
when :datetime then Time
|
24
|
+
when :date then Time
|
25
|
+
when :timestamp then Time
|
26
|
+
when :time then Time
|
27
|
+
when :text, :string then String
|
28
|
+
when :binary then String
|
29
|
+
when :boolean then Object
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def type_cast(value)
|
34
|
+
if type == :boolean
|
35
|
+
self.class.value_to_boolean(value)
|
36
|
+
else
|
37
|
+
value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def type_cast_code(var_name)
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Mysql2Adapter < MysqlAdapter
|
47
|
+
PRIMARY = "PRIMARY".freeze
|
48
|
+
ADAPTER_NAME = "Mysql2".freeze
|
49
|
+
|
50
|
+
def adapter_name
|
51
|
+
ADAPTER_NAME
|
52
|
+
end
|
53
|
+
|
54
|
+
# QUOTING ==================================================
|
55
|
+
def quote_string(string)
|
56
|
+
@connection.escape(string)
|
57
|
+
end
|
58
|
+
|
59
|
+
# CONNECTION MANAGEMENT ====================================
|
60
|
+
|
61
|
+
def active?
|
62
|
+
@connection.query 'select 1'
|
63
|
+
true
|
64
|
+
rescue Mysql2::Error
|
65
|
+
false
|
66
|
+
end
|
67
|
+
|
68
|
+
def reconnect!
|
69
|
+
reset!
|
70
|
+
end
|
71
|
+
|
72
|
+
def disconnect!
|
73
|
+
@connection = nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def reset!
|
77
|
+
@connection = Mysql2::Client.new(@config)
|
78
|
+
end
|
79
|
+
|
80
|
+
# DATABASE STATEMENTS ======================================
|
81
|
+
|
82
|
+
def select_values(sql, name = nil)
|
83
|
+
result = select_rows(sql, name)
|
84
|
+
result.map { |row| row.values.first }
|
85
|
+
end
|
86
|
+
|
87
|
+
def select_rows(sql, name = nil)
|
88
|
+
select(sql, name)
|
89
|
+
end
|
90
|
+
|
91
|
+
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
92
|
+
super sql, name
|
93
|
+
id_value || @connection.last_id
|
94
|
+
end
|
95
|
+
alias :create :insert_sql
|
96
|
+
|
97
|
+
# SCHEMA STATEMENTS ========================================
|
98
|
+
|
99
|
+
def tables(name = nil)
|
100
|
+
tables = []
|
101
|
+
execute("SHOW TABLES", name).each(:symbolize_keys => true) do |field|
|
102
|
+
tables << field.values.first
|
103
|
+
end
|
104
|
+
tables
|
105
|
+
end
|
106
|
+
|
107
|
+
def indexes(table_name, name = nil)
|
108
|
+
indexes = []
|
109
|
+
current_index = nil
|
110
|
+
result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name)
|
111
|
+
result.each(:symbolize_keys => true) do |row|
|
112
|
+
if current_index != row[:Key_name]
|
113
|
+
next if row[:Key_name] == PRIMARY # skip the primary key
|
114
|
+
current_index = row[:Key_name]
|
115
|
+
indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique] == 0, [])
|
116
|
+
end
|
117
|
+
|
118
|
+
indexes.last.columns << row[:Column_name]
|
119
|
+
end
|
120
|
+
indexes
|
121
|
+
end
|
122
|
+
|
123
|
+
def columns(table_name, name = nil)
|
124
|
+
sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
|
125
|
+
columns = []
|
126
|
+
result = execute(sql, :skip_logging)
|
127
|
+
result.each(:symbolize_keys => true) { |field|
|
128
|
+
columns << Mysql2Column.new(field[:Field], field[:Default], field[:Type], field[:Null] == "YES")
|
129
|
+
}
|
130
|
+
columns
|
131
|
+
end
|
132
|
+
|
133
|
+
def show_variable(name)
|
134
|
+
variables = select_all("SHOW VARIABLES LIKE '#{name}'")
|
135
|
+
variables.first[:Value] unless variables.empty?
|
136
|
+
end
|
137
|
+
|
138
|
+
def pk_and_sequence_for(table)
|
139
|
+
keys = []
|
140
|
+
result = execute("describe #{quote_table_name(table)}")
|
141
|
+
result.each(:symbolize_keys) do |row|
|
142
|
+
keys << row[:Field] if row[:Key] == "PRI"
|
143
|
+
end
|
144
|
+
keys.length == 1 ? [keys.first, nil] : nil
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
def connect
|
149
|
+
# no-op
|
150
|
+
end
|
151
|
+
|
152
|
+
def select(sql, name = nil)
|
153
|
+
execute(sql, name).to_a
|
154
|
+
end
|
155
|
+
|
156
|
+
def supports_views?
|
157
|
+
version[0] >= 5
|
158
|
+
end
|
159
|
+
|
160
|
+
def version
|
161
|
+
@version ||= @connection.info[:version].scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
data/lib/mysql2.rb
CHANGED
data/lib/mysql2/em.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'eventmachine' unless defined? EventMachine
|
4
|
+
require 'mysql2' unless defined? Mysql2
|
5
|
+
|
6
|
+
module Mysql2
|
7
|
+
module EM
|
8
|
+
class Client < ::Mysql2::Client
|
9
|
+
module Watcher
|
10
|
+
def initialize(client, deferable)
|
11
|
+
@client = client
|
12
|
+
@deferable = deferable
|
13
|
+
end
|
14
|
+
|
15
|
+
def notify_readable
|
16
|
+
begin
|
17
|
+
@deferable.succeed(@client.async_result)
|
18
|
+
rescue Exception => e
|
19
|
+
@deferable.fail(e)
|
20
|
+
end
|
21
|
+
detach
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
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
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/mysql2.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mysql2}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Brian Lopez"]
|
12
|
-
s.date = %q{2010-04-
|
12
|
+
s.date = %q{2010-04-15}
|
13
13
|
s.email = %q{seniorlopez@gmail.com}
|
14
14
|
s.extensions = ["ext/extconf.rb"]
|
15
15
|
s.extra_rdoc_files = [
|
@@ -22,14 +22,21 @@ Gem::Specification.new do |s|
|
|
22
22
|
"README.rdoc",
|
23
23
|
"Rakefile",
|
24
24
|
"VERSION",
|
25
|
+
"benchmark/active_record.rb",
|
25
26
|
"benchmark/escape.rb",
|
26
27
|
"benchmark/query.rb",
|
27
28
|
"benchmark/setup_db.rb",
|
29
|
+
"examples/eventmachine.rb",
|
28
30
|
"ext/extconf.rb",
|
29
31
|
"ext/mysql2_ext.c",
|
30
32
|
"ext/mysql2_ext.h",
|
33
|
+
"lib/active_record/connection_adapters/mysql2_adapter.rb",
|
34
|
+
"lib/arel/engines/sql/compilers/mysql2_compiler.rb",
|
31
35
|
"lib/mysql2.rb",
|
36
|
+
"lib/mysql2/em.rb",
|
32
37
|
"mysql2.gemspec",
|
38
|
+
"spec/active_record/active_record_spec.rb",
|
39
|
+
"spec/em/em_spec.rb",
|
33
40
|
"spec/mysql2/client_spec.rb",
|
34
41
|
"spec/mysql2/result_spec.rb",
|
35
42
|
"spec/rcov.opts",
|
@@ -42,9 +49,12 @@ Gem::Specification.new do |s|
|
|
42
49
|
s.rubygems_version = %q{1.3.6}
|
43
50
|
s.summary = %q{A simple, fast Mysql library for Ruby, binding to libmysql}
|
44
51
|
s.test_files = [
|
45
|
-
"spec/
|
52
|
+
"spec/active_record/active_record_spec.rb",
|
53
|
+
"spec/em/em_spec.rb",
|
54
|
+
"spec/mysql2/client_spec.rb",
|
46
55
|
"spec/mysql2/result_spec.rb",
|
47
|
-
"spec/spec_helper.rb"
|
56
|
+
"spec/spec_helper.rb",
|
57
|
+
"examples/eventmachine.rb"
|
48
58
|
]
|
49
59
|
|
50
60
|
if s.respond_to? :specification_version then
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
|
3
|
+
require 'active_record'
|
4
|
+
require 'active_record/connection_adapters/mysql2_adapter'
|
5
|
+
|
6
|
+
describe ActiveRecord::ConnectionAdapters::Mysql2Adapter do
|
7
|
+
it "should be able to connect" do
|
8
|
+
lambda {
|
9
|
+
ActiveRecord::Base.establish_connection(:adapter => 'mysql2')
|
10
|
+
}.should_not raise_error(Mysql2::Error)
|
11
|
+
end
|
12
|
+
|
13
|
+
context "once connected" do
|
14
|
+
before(:each) do
|
15
|
+
@connection = ActiveRecord::Base.connection
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be able to execute a raw query" do
|
19
|
+
@connection.execute("SELECT 1 as one").first['one'].should eql(1)
|
20
|
+
@connection.execute("SELECT NOW() as n").first['n'].class.should eql(Time)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/spec/em/em_spec.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
|
3
|
+
require 'mysql2/em'
|
4
|
+
|
5
|
+
describe Mysql2::EM::Client do
|
6
|
+
it "should support async queries" do
|
7
|
+
results = []
|
8
|
+
EM.run do
|
9
|
+
client1 = Mysql2::EM::Client.new
|
10
|
+
defer1 = client1.query "SELECT sleep(0.05) as first_query"
|
11
|
+
defer1.callback do |result|
|
12
|
+
results << result.first
|
13
|
+
EM.stop_event_loop
|
14
|
+
end
|
15
|
+
|
16
|
+
client2 = Mysql2::EM::Client.new
|
17
|
+
defer2 = client2.query "SELECT sleep(0.025) second_query"
|
18
|
+
defer2.callback do |result|
|
19
|
+
results << result.first
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
results[0].keys.should include("second_query")
|
24
|
+
results[1].keys.should include("first_query")
|
25
|
+
end
|
26
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 3
|
9
|
+
version: 0.1.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Brian Lopez
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-04-
|
17
|
+
date: 2010-04-15 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -33,14 +33,21 @@ files:
|
|
33
33
|
- README.rdoc
|
34
34
|
- Rakefile
|
35
35
|
- VERSION
|
36
|
+
- benchmark/active_record.rb
|
36
37
|
- benchmark/escape.rb
|
37
38
|
- benchmark/query.rb
|
38
39
|
- benchmark/setup_db.rb
|
40
|
+
- examples/eventmachine.rb
|
39
41
|
- ext/extconf.rb
|
40
42
|
- ext/mysql2_ext.c
|
41
43
|
- ext/mysql2_ext.h
|
44
|
+
- lib/active_record/connection_adapters/mysql2_adapter.rb
|
45
|
+
- lib/arel/engines/sql/compilers/mysql2_compiler.rb
|
42
46
|
- lib/mysql2.rb
|
47
|
+
- lib/mysql2/em.rb
|
43
48
|
- mysql2.gemspec
|
49
|
+
- spec/active_record/active_record_spec.rb
|
50
|
+
- spec/em/em_spec.rb
|
44
51
|
- spec/mysql2/client_spec.rb
|
45
52
|
- spec/mysql2/result_spec.rb
|
46
53
|
- spec/rcov.opts
|
@@ -78,6 +85,9 @@ signing_key:
|
|
78
85
|
specification_version: 3
|
79
86
|
summary: A simple, fast Mysql library for Ruby, binding to libmysql
|
80
87
|
test_files:
|
88
|
+
- spec/active_record/active_record_spec.rb
|
89
|
+
- spec/em/em_spec.rb
|
81
90
|
- spec/mysql2/client_spec.rb
|
82
91
|
- spec/mysql2/result_spec.rb
|
83
92
|
- spec/spec_helper.rb
|
93
|
+
- examples/eventmachine.rb
|