mysql2 0.1.9 → 0.2.0

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.
@@ -1,6 +1,18 @@
1
1
  module Mysql2
2
2
  class Client
3
- def initialize opts = {}
3
+ attr_reader :query_options
4
+ @@default_query_options = {
5
+ :as => :hash,
6
+ :async => false,
7
+ :cast_booleans => false,
8
+ :symbolize_keys => false,
9
+ :database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in
10
+ :application_timezone => nil # timezone Mysql2 will convert to before handing the object back to the caller
11
+ }
12
+
13
+ def initialize(opts = {})
14
+ @query_options = @@default_query_options.dup
15
+
4
16
  init_connection
5
17
 
6
18
  [:reconnect, :connect_timeout].each do |key|
@@ -22,6 +34,10 @@ module Mysql2
22
34
  connect user, pass, host, port, database, socket
23
35
  end
24
36
 
37
+ def self.default_query_options
38
+ @@default_query_options
39
+ end
40
+
25
41
  # NOTE: from ruby-mysql
26
42
  if defined? Encoding
27
43
  CHARSET_MAP = {
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mysql2}
8
- s.version = "0.1.9"
8
+ s.version = "0.2.0"
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-07-17}
12
+ s.date = %q{2010-08-16}
13
13
  s.email = %q{seniorlopez@gmail.com}
14
14
  s.extensions = ["ext/mysql2/extconf.rb"]
15
15
  s.extra_rdoc_files = [
@@ -23,19 +23,23 @@ Gem::Specification.new do |s|
23
23
  "Rakefile",
24
24
  "VERSION",
25
25
  "benchmark/active_record.rb",
26
+ "benchmark/allocations.rb",
26
27
  "benchmark/escape.rb",
27
28
  "benchmark/query_with_mysql_casting.rb",
28
29
  "benchmark/query_without_mysql_casting.rb",
29
30
  "benchmark/sequel.rb",
30
31
  "benchmark/setup_db.rb",
32
+ "benchmark/thread_alone.rb",
31
33
  "examples/eventmachine.rb",
34
+ "examples/threaded.rb",
35
+ "ext/mysql2/client.c",
36
+ "ext/mysql2/client.h",
32
37
  "ext/mysql2/extconf.rb",
33
38
  "ext/mysql2/mysql2_ext.c",
34
39
  "ext/mysql2/mysql2_ext.h",
35
40
  "ext/mysql2/result.c",
36
41
  "ext/mysql2/result.h",
37
42
  "lib/active_record/connection_adapters/em_mysql2_adapter.rb",
38
- "lib/active_record/connection_adapters/mysql2_adapter.rb",
39
43
  "lib/active_record/fiber_patches.rb",
40
44
  "lib/arel/engines/sql/compilers/mysql2_compiler.rb",
41
45
  "lib/mysql2.rb",
@@ -43,16 +47,17 @@ Gem::Specification.new do |s|
43
47
  "lib/mysql2/em.rb",
44
48
  "lib/mysql2/error.rb",
45
49
  "lib/mysql2/result.rb",
46
- "lib/sequel/adapters/mysql2.rb",
47
50
  "mysql2.gemspec",
48
- "spec/active_record/active_record_spec.rb",
49
51
  "spec/em/em_spec.rb",
50
52
  "spec/mysql2/client_spec.rb",
51
53
  "spec/mysql2/error_spec.rb",
52
54
  "spec/mysql2/result_spec.rb",
53
55
  "spec/rcov.opts",
54
56
  "spec/spec.opts",
55
- "spec/spec_helper.rb"
57
+ "spec/spec_helper.rb",
58
+ "tasks/benchmarks.rake",
59
+ "tasks/compile.rake",
60
+ "tasks/vendor_mysql.rake"
56
61
  ]
57
62
  s.homepage = %q{http://github.com/brianmario/mysql2}
58
63
  s.rdoc_options = ["--charset=UTF-8"]
@@ -60,13 +65,13 @@ Gem::Specification.new do |s|
60
65
  s.rubygems_version = %q{1.3.7}
61
66
  s.summary = %q{A simple, fast Mysql library for Ruby, binding to libmysql}
62
67
  s.test_files = [
63
- "spec/active_record/active_record_spec.rb",
64
- "spec/em/em_spec.rb",
68
+ "spec/em/em_spec.rb",
65
69
  "spec/mysql2/client_spec.rb",
66
70
  "spec/mysql2/error_spec.rb",
67
71
  "spec/mysql2/result_spec.rb",
68
72
  "spec/spec_helper.rb",
69
- "examples/eventmachine.rb"
73
+ "examples/eventmachine.rb",
74
+ "examples/threaded.rb"
70
75
  ]
71
76
 
72
77
  if s.respond_to? :specification_version then
@@ -14,6 +14,10 @@ describe Mysql2::Client do
14
14
  end
15
15
  end
16
16
 
17
+ it "should have a global default_query_options hash" do
18
+ Mysql2::Client.should respond_to(:default_query_options)
19
+ end
20
+
17
21
  it "should be able to connect via SSL options" do
18
22
  pending("DON'T WORRY, THIS TEST PASSES :) - but is machine-specific. You need to have MySQL running with SSL configured and enabled. Then update the paths in this test to your needs and remove the pending state.")
19
23
  ssl_client = nil
@@ -38,26 +42,46 @@ describe Mysql2::Client do
38
42
  end
39
43
 
40
44
  it "should respond to #close" do
41
- @client.should respond_to :close
45
+ @client.should respond_to(:close)
42
46
  end
43
47
 
44
48
  it "should be able to close properly" do
45
49
  @client.close.should be_nil
46
50
  end
47
51
 
48
- it "should raise an exception when closed twice" do
49
- @client.close.should be_nil
50
- lambda {
51
- @client.close
52
- }.should raise_error(Mysql2::Error)
52
+ it "should respond to #query" do
53
+ @client.should respond_to(:query)
53
54
  end
54
55
 
55
- it "should respond to #query" do
56
- @client.should respond_to :query
56
+ context "#query" do
57
+ it "should accept an options hash that inherits from Mysql2::Client.default_query_options" do
58
+ @client.query "SELECT 1", :something => :else
59
+ @client.query_options.should eql(@client.query_options.merge(:something => :else))
60
+ end
61
+
62
+ it "should return results as a hash by default" do
63
+ @client.query("SELECT 1").first.class.should eql(Hash)
64
+ end
65
+
66
+ it "should be able to return results as an array" do
67
+ @client.query("SELECT 1", :as => :array).first.class.should eql(Array)
68
+ @client.query("SELECT 1").each(:as => :array)
69
+ end
70
+
71
+ it "should be able to return results with symbolized keys" do
72
+ @client.query("SELECT 1", :symbolize_keys => true).first.keys[0].class.should eql(Symbol)
73
+ end
74
+
75
+ it "should not allow another query to be sent without fetching a result first" do
76
+ @client.query("SELECT 1", :async => true)
77
+ lambda {
78
+ @client.query("SELECT 1")
79
+ }.should raise_error(Mysql2::Error)
80
+ end
57
81
  end
58
82
 
59
83
  it "should respond to #escape" do
60
- @client.should respond_to :escape
84
+ @client.should respond_to(:escape)
61
85
  end
62
86
 
63
87
  it "#escape should return a new SQL-escape version of the passed string" do
@@ -70,7 +94,7 @@ describe Mysql2::Client do
70
94
  end
71
95
 
72
96
  it "should respond to #info" do
73
- @client.should respond_to :info
97
+ @client.should respond_to(:info)
74
98
  end
75
99
 
76
100
  it "#info should return a hash containing the client version ID and String" do
@@ -102,7 +126,7 @@ describe Mysql2::Client do
102
126
  end
103
127
 
104
128
  it "should respond to #server_info" do
105
- @client.should respond_to :server_info
129
+ @client.should respond_to(:server_info)
106
130
  end
107
131
 
108
132
  it "#server_info should return a hash containing the client version ID and String" do
@@ -134,7 +158,7 @@ describe Mysql2::Client do
134
158
  end
135
159
 
136
160
  it "should respond to #socket" do
137
- @client.should respond_to :socket
161
+ @client.should respond_to(:socket)
138
162
  end
139
163
 
140
164
  it "#socket should return a Fixnum (file descriptor from C)" do
@@ -152,6 +176,20 @@ describe Mysql2::Client do
152
176
  }.should_not raise_error(Mysql2::Error)
153
177
  end
154
178
 
179
+ it "threaded queries should be supported" do
180
+ threads, results = [], {}
181
+ connect = lambda{ Mysql2::Client.new(:host => "localhost", :username => "root") }
182
+ Timeout.timeout(0.7) do
183
+ 5.times {
184
+ threads << Thread.new do
185
+ results[Thread.current.object_id] = connect.call.query("SELECT sleep(0.5) as result")
186
+ end
187
+ }
188
+ end
189
+ threads.each{|t| t.join }
190
+ results.keys.sort.should eql(threads.map{|t| t.object_id }.sort)
191
+ end
192
+
155
193
  it "evented async queries should be supported" do
156
194
  # should immediately return nil
157
195
  @client.query("SELECT sleep(0.1)", :async => true).should eql(nil)
@@ -2,7 +2,7 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe Mysql2::Result do
5
- before(:all) do
5
+ before(:each) do
6
6
  @client = Mysql2::Client.new :host => "localhost", :username => "root"
7
7
  end
8
8
 
@@ -15,7 +15,7 @@ describe Mysql2::Result do
15
15
  end
16
16
 
17
17
  it "should respond to #each" do
18
- @result.should respond_to :each
18
+ @result.should respond_to(:each)
19
19
  end
20
20
 
21
21
  it "should raise a Mysql2::Error exception upon a bad query" do
@@ -37,18 +37,23 @@ describe Mysql2::Result do
37
37
 
38
38
  it "should yield rows as hash's with symbol keys if :symbolize_keys was set to true" do
39
39
  @result.each(:symbolize_keys => true) do |row|
40
- row.class.should eql(Hash)
41
40
  row.keys.first.class.should eql(Symbol)
42
41
  end
43
42
  end
44
43
 
44
+ it "should be able to return results as an array" do
45
+ @result.each(:as => :array) do |row|
46
+ row.class.should eql(Array)
47
+ end
48
+ end
49
+
45
50
  it "should cache previously yielded results" do
46
51
  @result.first.should eql(@result.first)
47
52
  end
48
53
  end
49
54
 
50
55
  context "#fields" do
51
- before(:all) do
56
+ before(:each) do
52
57
  @client.query "USE test"
53
58
  @test_result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1")
54
59
  end
@@ -64,67 +69,11 @@ describe Mysql2::Result do
64
69
  end
65
70
 
66
71
  context "row data type mapping" do
67
- before(:all) do
72
+ before(:each) do
68
73
  @client.query "USE test"
69
- @client.query %[
70
- CREATE TABLE IF NOT EXISTS mysql2_test (
71
- id MEDIUMINT NOT NULL AUTO_INCREMENT,
72
- null_test VARCHAR(10),
73
- bit_test BIT(64),
74
- tiny_int_test TINYINT,
75
- small_int_test SMALLINT,
76
- medium_int_test MEDIUMINT,
77
- int_test INT,
78
- big_int_test BIGINT,
79
- float_test FLOAT(10,3),
80
- double_test DOUBLE(10,3),
81
- decimal_test DECIMAL(10,3),
82
- date_test DATE,
83
- date_time_test DATETIME,
84
- timestamp_test TIMESTAMP,
85
- time_test TIME,
86
- year_test YEAR(4),
87
- char_test CHAR(10),
88
- varchar_test VARCHAR(10),
89
- binary_test BINARY(10),
90
- varbinary_test VARBINARY(10),
91
- tiny_blob_test TINYBLOB,
92
- tiny_text_test TINYTEXT,
93
- blob_test BLOB,
94
- text_test TEXT,
95
- medium_blob_test MEDIUMBLOB,
96
- medium_text_test MEDIUMTEXT,
97
- long_blob_test LONGBLOB,
98
- long_text_test LONGTEXT,
99
- enum_test ENUM('val1', 'val2'),
100
- set_test SET('val1', 'val2'),
101
- PRIMARY KEY (id)
102
- )
103
- ]
104
- @client.query %[
105
- INSERT INTO mysql2_test (
106
- null_test, bit_test, tiny_int_test, small_int_test, medium_int_test, int_test, big_int_test,
107
- float_test, double_test, decimal_test, date_test, date_time_test, timestamp_test, time_test,
108
- year_test, char_test, varchar_test, binary_test, varbinary_test, tiny_blob_test,
109
- tiny_text_test, blob_test, text_test, medium_blob_test, medium_text_test,
110
- long_blob_test, long_text_test, enum_test, set_test
111
- )
112
-
113
- VALUES (
114
- NULL, b'101', 1, 10, 10, 10, 10,
115
- 10.3, 10.3, 10.3, '2010-4-4', '2010-4-4 11:44:00', '2010-4-4 11:44:00', '11:44:00',
116
- 2009, "test", "test", "test", "test", "test",
117
- "test", "test", "test", "test", "test",
118
- "test", "test", 'val1', 'val1,val2'
119
- )
120
- ]
121
74
  @test_result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
122
75
  end
123
76
 
124
- after(:all) do
125
- @client.query("DELETE FROM mysql2_test WHERE id=#{@test_result['id']}")
126
- end
127
-
128
77
  it "should return nil for a NULL value" do
129
78
  @test_result['null_test'].class.should eql(NilClass)
130
79
  @test_result['null_test'].should eql(nil)
@@ -140,6 +89,20 @@ describe Mysql2::Result do
140
89
  @test_result['tiny_int_test'].should eql(1)
141
90
  end
142
91
 
92
+ it "should return TrueClass or FalseClass for a TINYINT value if :cast_booleans is enabled" do
93
+ @client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (1)'
94
+ id1 = @client.last_id
95
+ @client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (0)'
96
+ id2 = @client.last_id
97
+
98
+ result1 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = 1 LIMIT 1', :cast_booleans => true
99
+ result2 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = 0 LIMIT 1', :cast_booleans => true
100
+ result1.first['bool_cast_test'].should be_true
101
+ result2.first['bool_cast_test'].should be_false
102
+
103
+ @client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2})"
104
+ end
105
+
143
106
  it "should return Fixnum for a SMALLINT value" do
144
107
  [Fixnum, Bignum].should include(@test_result['small_int_test'].class)
145
108
  @test_result['small_int_test'].should eql(10)
@@ -192,11 +155,7 @@ describe Mysql2::Result do
192
155
 
193
156
  it "should return Time for a TIME value" do
194
157
  @test_result['time_test'].class.should eql(Time)
195
- if RUBY_VERSION >= "1.9.2"
196
- @test_result['time_test'].strftime("%F %T").should eql('0000-01-01 11:44:00')
197
- else
198
- @test_result['time_test'].strftime("%F %T").should eql('2000-01-01 11:44:00')
199
- end
158
+ @test_result['time_test'].strftime("%F %T").should eql('2000-01-01 11:44:00')
200
159
  end
201
160
 
202
161
  it "should return Date for a DATE value" do
@@ -3,3 +3,65 @@ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..')
3
3
  $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
4
 
5
5
  require 'mysql2'
6
+ require 'timeout'
7
+
8
+ Spec::Runner.configure do |config|
9
+ config.before(:all) do
10
+ client = Mysql2::Client.new :database => 'test'
11
+ client.query %[
12
+ CREATE TABLE IF NOT EXISTS mysql2_test (
13
+ id MEDIUMINT NOT NULL AUTO_INCREMENT,
14
+ null_test VARCHAR(10),
15
+ bit_test BIT(64),
16
+ tiny_int_test TINYINT,
17
+ bool_cast_test TINYINT(1),
18
+ small_int_test SMALLINT,
19
+ medium_int_test MEDIUMINT,
20
+ int_test INT,
21
+ big_int_test BIGINT,
22
+ float_test FLOAT(10,3),
23
+ float_zero_test FLOAT(10,3),
24
+ double_test DOUBLE(10,3),
25
+ decimal_test DECIMAL(10,3),
26
+ decimal_zero_test DECIMAL(10,3),
27
+ date_test DATE,
28
+ date_time_test DATETIME,
29
+ timestamp_test TIMESTAMP,
30
+ time_test TIME,
31
+ year_test YEAR(4),
32
+ char_test CHAR(10),
33
+ varchar_test VARCHAR(10),
34
+ binary_test BINARY(10),
35
+ varbinary_test VARBINARY(10),
36
+ tiny_blob_test TINYBLOB,
37
+ tiny_text_test TINYTEXT,
38
+ blob_test BLOB,
39
+ text_test TEXT,
40
+ medium_blob_test MEDIUMBLOB,
41
+ medium_text_test MEDIUMTEXT,
42
+ long_blob_test LONGBLOB,
43
+ long_text_test LONGTEXT,
44
+ enum_test ENUM('val1', 'val2'),
45
+ set_test SET('val1', 'val2'),
46
+ PRIMARY KEY (id)
47
+ )
48
+ ]
49
+ client.query %[
50
+ INSERT INTO mysql2_test (
51
+ null_test, bit_test, tiny_int_test, bool_cast_test, small_int_test, medium_int_test, int_test, big_int_test,
52
+ float_test, float_zero_test, double_test, decimal_test, decimal_zero_test, date_test, date_time_test, timestamp_test, time_test,
53
+ year_test, char_test, varchar_test, binary_test, varbinary_test, tiny_blob_test,
54
+ tiny_text_test, blob_test, text_test, medium_blob_test, medium_text_test,
55
+ long_blob_test, long_text_test, enum_test, set_test
56
+ )
57
+
58
+ VALUES (
59
+ NULL, b'101', 1, 1, 10, 10, 10, 10,
60
+ 10.3, 0, 10.3, 10.3, 0, '2010-4-4', '2010-4-4 11:44:00', '2010-4-4 11:44:00', '11:44:00',
61
+ 2009, "test", "test", "test", "test", "test",
62
+ "test", "test", "test", "test", "test",
63
+ "test", "test", 'val1', 'val1,val2'
64
+ )
65
+ ]
66
+ end
67
+ end
@@ -0,0 +1,8 @@
1
+ namespace :bench do
2
+ [ :active_record, :escape, :query_with_mysql_casting,
3
+ :query_without_mysql_casting, :sequel, :allocations,
4
+ :thread_alone].each do |feature|
5
+ desc "Run #{feature} benchmarks"
6
+ task(feature){ ruby "benchmark/#{feature}.rb" }
7
+ end
8
+ end
@@ -0,0 +1,19 @@
1
+ gem 'rake-compiler', '~> 0.7.1'
2
+ require "rake/extensiontask"
3
+
4
+ MYSQL_VERSION = "5.1.49"
5
+ MYSQL_MIRROR = ENV['MYSQL_MIRROR'] || "http://mysql.localhost.net.ar"
6
+
7
+ Rake::ExtensionTask.new("mysql2", JEWELER.gemspec) do |ext|
8
+ # reference where the vendored MySQL got extracted
9
+ mysql_lib = File.expand_path(File.join(File.dirname(__FILE__), '..', 'vendor', "mysql-#{MYSQL_VERSION}-win32"))
10
+
11
+ # automatically add build options to avoid need of manual input
12
+ if RUBY_PLATFORM =~ /mswin|mingw/ then
13
+ ext.config_options << "--with-mysql-include=#{mysql_lib}/include"
14
+ ext.config_options << "--with-mysql-lib=#{mysql_lib}/lib/opt"
15
+ end
16
+
17
+ ext.lib_dir = File.join 'lib', 'mysql2'
18
+ end
19
+ Rake::Task[:spec].prerequisites << :compile