mysql2 0.1.2 → 0.1.3
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.
- 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
|