mysql2 0.1.9 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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