ghazel-mysql2 0.2.6.1

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.
Files changed (46) hide show
  1. data/.gitignore +12 -0
  2. data/.rspec +2 -0
  3. data/CHANGELOG.md +117 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.rdoc +240 -0
  6. data/Rakefile +5 -0
  7. data/VERSION +1 -0
  8. data/benchmark/active_record.rb +53 -0
  9. data/benchmark/allocations.rb +33 -0
  10. data/benchmark/escape.rb +39 -0
  11. data/benchmark/query_with_mysql_casting.rb +83 -0
  12. data/benchmark/query_without_mysql_casting.rb +50 -0
  13. data/benchmark/sequel.rb +39 -0
  14. data/benchmark/setup_db.rb +115 -0
  15. data/examples/eventmachine.rb +21 -0
  16. data/examples/threaded.rb +20 -0
  17. data/ext/mysql2/client.c +728 -0
  18. data/ext/mysql2/client.h +41 -0
  19. data/ext/mysql2/extconf.rb +69 -0
  20. data/ext/mysql2/mysql2_ext.c +12 -0
  21. data/ext/mysql2/mysql2_ext.h +38 -0
  22. data/ext/mysql2/result.c +478 -0
  23. data/ext/mysql2/result.h +20 -0
  24. data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +62 -0
  25. data/lib/active_record/connection_adapters/mysql2_adapter.rb +657 -0
  26. data/lib/active_record/fiber_patches.rb +104 -0
  27. data/lib/arel/engines/sql/compilers/mysql2_compiler.rb +11 -0
  28. data/lib/mysql2.rb +16 -0
  29. data/lib/mysql2/client.rb +240 -0
  30. data/lib/mysql2/em.rb +37 -0
  31. data/lib/mysql2/em_fiber.rb +29 -0
  32. data/lib/mysql2/error.rb +15 -0
  33. data/lib/mysql2/result.rb +5 -0
  34. data/mysql2.gemspec +90 -0
  35. data/spec/em/em_spec.rb +49 -0
  36. data/spec/mysql2/client_spec.rb +367 -0
  37. data/spec/mysql2/error_spec.rb +25 -0
  38. data/spec/mysql2/result_spec.rb +318 -0
  39. data/spec/rcov.opts +3 -0
  40. data/spec/spec_helper.rb +67 -0
  41. data/tasks/benchmarks.rake +8 -0
  42. data/tasks/compile.rake +54 -0
  43. data/tasks/jeweler.rake +17 -0
  44. data/tasks/rspec.rake +16 -0
  45. data/tasks/vendor_mysql.rake +41 -0
  46. metadata +119 -0
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+
4
+ describe Mysql2::Error do
5
+ before(:each) do
6
+ @error = Mysql2::Error.new "testing"
7
+ end
8
+
9
+ it "should respond to #error_number" do
10
+ @error.should respond_to(:error_number)
11
+ end
12
+
13
+ it "should respond to #sql_state" do
14
+ @error.should respond_to(:sql_state)
15
+ end
16
+
17
+ # Mysql gem compatibility
18
+ it "should alias #error_number to #errno" do
19
+ @error.should respond_to(:errno)
20
+ end
21
+
22
+ it "should alias #message to #error" do
23
+ @error.should respond_to(:error)
24
+ end
25
+ end
@@ -0,0 +1,318 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+
4
+ describe Mysql2::Result do
5
+ before(:each) do
6
+ @client = Mysql2::Client.new :host => "localhost", :username => "root"
7
+ end
8
+
9
+ before(:each) do
10
+ @result = @client.query "SELECT 1"
11
+ end
12
+
13
+ it "should have included Enumerable" do
14
+ Mysql2::Result.ancestors.include?(Enumerable).should be_true
15
+ end
16
+
17
+ it "should respond to #each" do
18
+ @result.should respond_to(:each)
19
+ end
20
+
21
+ it "should raise a Mysql2::Error exception upon a bad query" do
22
+ lambda {
23
+ @client.query "bad sql"
24
+ }.should raise_error(Mysql2::Error)
25
+
26
+ lambda {
27
+ @client.query "SELECT 1"
28
+ }.should_not raise_error(Mysql2::Error)
29
+ end
30
+
31
+ context "#each" do
32
+ it "should yield rows as hash's" do
33
+ @result.each do |row|
34
+ row.class.should eql(Hash)
35
+ end
36
+ end
37
+
38
+ it "should yield rows as hash's with symbol keys if :symbolize_keys was set to true" do
39
+ @result.each(:symbolize_keys => true) do |row|
40
+ row.keys.first.class.should eql(Symbol)
41
+ end
42
+ end
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
+
50
+ it "should cache previously yielded results by default" do
51
+ @result.first.object_id.should eql(@result.first.object_id)
52
+ end
53
+
54
+ it "should not cache previously yielded results if cache_rows is disabled" do
55
+ result = @client.query "SELECT 1", :cache_rows => false
56
+ result.first.object_id.should_not eql(result.first.object_id)
57
+ end
58
+ end
59
+
60
+ context "#fields" do
61
+ before(:each) do
62
+ @client.query "USE test"
63
+ @test_result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1")
64
+ end
65
+
66
+ it "method should exist" do
67
+ @test_result.should respond_to(:fields)
68
+ end
69
+
70
+ it "should return an array of field names in proper order" do
71
+ result = @client.query "SELECT 'a', 'b', 'c'"
72
+ result.fields.should eql(['a', 'b', 'c'])
73
+ end
74
+ end
75
+
76
+ context "row data type mapping" do
77
+ before(:each) do
78
+ @client.query "USE test"
79
+ @test_result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
80
+ end
81
+
82
+ it "should return nil for a NULL value" do
83
+ @test_result['null_test'].class.should eql(NilClass)
84
+ @test_result['null_test'].should eql(nil)
85
+ end
86
+
87
+ it "should return Fixnum for a BIT value" do
88
+ @test_result['bit_test'].class.should eql(String)
89
+ @test_result['bit_test'].should eql("\000\000\000\000\000\000\000\005")
90
+ end
91
+
92
+ it "should return Fixnum for a TINYINT value" do
93
+ [Fixnum, Bignum].should include(@test_result['tiny_int_test'].class)
94
+ @test_result['tiny_int_test'].should eql(1)
95
+ end
96
+
97
+ it "should return TrueClass or FalseClass for a TINYINT value if :cast_booleans is enabled" do
98
+ @client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (1)'
99
+ id1 = @client.last_id
100
+ @client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (0)'
101
+ id2 = @client.last_id
102
+
103
+ result1 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = 1 LIMIT 1', :cast_booleans => true
104
+ result2 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = 0 LIMIT 1', :cast_booleans => true
105
+ result1.first['bool_cast_test'].should be_true
106
+ result2.first['bool_cast_test'].should be_false
107
+
108
+ @client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2})"
109
+ end
110
+
111
+ it "should return Fixnum for a SMALLINT value" do
112
+ [Fixnum, Bignum].should include(@test_result['small_int_test'].class)
113
+ @test_result['small_int_test'].should eql(10)
114
+ end
115
+
116
+ it "should return Fixnum for a MEDIUMINT value" do
117
+ [Fixnum, Bignum].should include(@test_result['medium_int_test'].class)
118
+ @test_result['medium_int_test'].should eql(10)
119
+ end
120
+
121
+ it "should return Fixnum for an INT value" do
122
+ [Fixnum, Bignum].should include(@test_result['int_test'].class)
123
+ @test_result['int_test'].should eql(10)
124
+ end
125
+
126
+ it "should return Fixnum for a BIGINT value" do
127
+ [Fixnum, Bignum].should include(@test_result['big_int_test'].class)
128
+ @test_result['big_int_test'].should eql(10)
129
+ end
130
+
131
+ it "should return Fixnum for a YEAR value" do
132
+ [Fixnum, Bignum].should include(@test_result['year_test'].class)
133
+ @test_result['year_test'].should eql(2009)
134
+ end
135
+
136
+ it "should return BigDecimal for a DECIMAL value" do
137
+ @test_result['decimal_test'].class.should eql(BigDecimal)
138
+ @test_result['decimal_test'].should eql(10.3)
139
+ end
140
+
141
+ it "should return Float for a FLOAT value" do
142
+ @test_result['float_test'].class.should eql(Float)
143
+ @test_result['float_test'].should eql(10.3)
144
+ end
145
+
146
+ it "should return Float for a DOUBLE value" do
147
+ @test_result['double_test'].class.should eql(Float)
148
+ @test_result['double_test'].should eql(10.3)
149
+ end
150
+
151
+ it "should return Time for a DATETIME value when within the supported range" do
152
+ @test_result['date_time_test'].class.should eql(Time)
153
+ @test_result['date_time_test'].strftime("%F %T").should eql('2010-04-04 11:44:00')
154
+ end
155
+
156
+ it "should return DateTime for a DATETIME value when outside the supported range" do
157
+ r = @client.query("SELECT CAST('1901-1-1 01:01:01' AS DATETIME) as test")
158
+ r.first['test'].class.should eql(DateTime)
159
+ end
160
+
161
+ it "should return Time for a TIMESTAMP value when within the supported range" do
162
+ @test_result['timestamp_test'].class.should eql(Time)
163
+ @test_result['timestamp_test'].strftime("%F %T").should eql('2010-04-04 11:44:00')
164
+ end
165
+
166
+ it "should return Time for a TIME value" do
167
+ @test_result['time_test'].class.should eql(Time)
168
+ @test_result['time_test'].strftime("%F %T").should eql('2000-01-01 11:44:00')
169
+ end
170
+
171
+ it "should return Date for a DATE value" do
172
+ @test_result['date_test'].class.should eql(Date)
173
+ @test_result['date_test'].strftime("%F").should eql('2010-04-04')
174
+ end
175
+
176
+ it "should return String for an ENUM value" do
177
+ @test_result['enum_test'].class.should eql(String)
178
+ @test_result['enum_test'].should eql('val1')
179
+ end
180
+
181
+ if defined? Encoding
182
+ context "string encoding for ENUM values" do
183
+ it "should default to the connection's encoding if Encoding.default_internal is nil" do
184
+ Encoding.default_internal = nil
185
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
186
+ result['enum_test'].encoding.should eql(Encoding.find('utf-8'))
187
+
188
+ client2 = Mysql2::Client.new :encoding => 'ascii'
189
+ client2.query "USE test"
190
+ result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
191
+ result['enum_test'].encoding.should eql(Encoding.find('us-ascii'))
192
+ end
193
+
194
+ it "should use Encoding.default_internal" do
195
+ Encoding.default_internal = Encoding.find('utf-8')
196
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
197
+ result['enum_test'].encoding.should eql(Encoding.default_internal)
198
+ Encoding.default_internal = Encoding.find('us-ascii')
199
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
200
+ result['enum_test'].encoding.should eql(Encoding.default_internal)
201
+ end
202
+ end
203
+ end
204
+
205
+ it "should return String for a SET value" do
206
+ @test_result['set_test'].class.should eql(String)
207
+ @test_result['set_test'].should eql('val1,val2')
208
+ end
209
+
210
+ if defined? Encoding
211
+ context "string encoding for SET values" do
212
+ it "should default to the connection's encoding if Encoding.default_internal is nil" do
213
+ Encoding.default_internal = nil
214
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
215
+ result['set_test'].encoding.should eql(Encoding.find('utf-8'))
216
+
217
+ client2 = Mysql2::Client.new :encoding => 'ascii'
218
+ client2.query "USE test"
219
+ result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
220
+ result['set_test'].encoding.should eql(Encoding.find('us-ascii'))
221
+ end
222
+
223
+ it "should use Encoding.default_internal" do
224
+ Encoding.default_internal = Encoding.find('utf-8')
225
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
226
+ result['set_test'].encoding.should eql(Encoding.default_internal)
227
+ Encoding.default_internal = Encoding.find('us-ascii')
228
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
229
+ result['set_test'].encoding.should eql(Encoding.default_internal)
230
+ end
231
+ end
232
+ end
233
+
234
+ it "should return String for a BINARY value" do
235
+ @test_result['binary_test'].class.should eql(String)
236
+ @test_result['binary_test'].should eql("test#{"\000"*6}")
237
+ end
238
+
239
+ if defined? Encoding
240
+ context "string encoding for BINARY values" do
241
+ it "should default to binary if Encoding.default_internal is nil" do
242
+ Encoding.default_internal = nil
243
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
244
+ result['binary_test'].encoding.should eql(Encoding.find('binary'))
245
+ end
246
+
247
+ it "should not use Encoding.default_internal" do
248
+ Encoding.default_internal = Encoding.find('utf-8')
249
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
250
+ result['binary_test'].encoding.should eql(Encoding.find('binary'))
251
+ Encoding.default_internal = Encoding.find('us-ascii')
252
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
253
+ result['binary_test'].encoding.should eql(Encoding.find('binary'))
254
+ end
255
+ end
256
+ end
257
+
258
+ {
259
+ 'char_test' => 'CHAR',
260
+ 'varchar_test' => 'VARCHAR',
261
+ 'varbinary_test' => 'VARBINARY',
262
+ 'tiny_blob_test' => 'TINYBLOB',
263
+ 'tiny_text_test' => 'TINYTEXT',
264
+ 'blob_test' => 'BLOB',
265
+ 'text_test' => 'TEXT',
266
+ 'medium_blob_test' => 'MEDIUMBLOB',
267
+ 'medium_text_test' => 'MEDIUMTEXT',
268
+ 'long_blob_test' => 'LONGBLOB',
269
+ 'long_text_test' => 'LONGTEXT'
270
+ }.each do |field, type|
271
+ it "should return a String for #{type}" do
272
+ @test_result[field].class.should eql(String)
273
+ @test_result[field].should eql("test")
274
+ end
275
+
276
+ if defined? Encoding
277
+ context "string encoding for #{type} values" do
278
+ if ['VARBINARY', 'TINYBLOB', 'BLOB', 'MEDIUMBLOB', 'LONGBLOB'].include?(type)
279
+ it "should default to binary if Encoding.default_internal is nil" do
280
+ Encoding.default_internal = nil
281
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
282
+ result['binary_test'].encoding.should eql(Encoding.find('binary'))
283
+ end
284
+
285
+ it "should not use Encoding.default_internal" do
286
+ Encoding.default_internal = Encoding.find('utf-8')
287
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
288
+ result['binary_test'].encoding.should eql(Encoding.find('binary'))
289
+ Encoding.default_internal = Encoding.find('us-ascii')
290
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
291
+ result['binary_test'].encoding.should eql(Encoding.find('binary'))
292
+ end
293
+ else
294
+ it "should default to utf-8 if Encoding.default_internal is nil" do
295
+ Encoding.default_internal = nil
296
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
297
+ result[field].encoding.should eql(Encoding.find('utf-8'))
298
+
299
+ client2 = Mysql2::Client.new :encoding => 'ascii'
300
+ client2.query "USE test"
301
+ result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
302
+ result[field].encoding.should eql(Encoding.find('us-ascii'))
303
+ end
304
+
305
+ it "should use Encoding.default_internal" do
306
+ Encoding.default_internal = Encoding.find('utf-8')
307
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
308
+ result[field].encoding.should eql(Encoding.default_internal)
309
+ Encoding.default_internal = Encoding.find('us-ascii')
310
+ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
311
+ result[field].encoding.should eql(Encoding.default_internal)
312
+ end
313
+ end
314
+ end
315
+ end
316
+ end
317
+ end
318
+ end
data/spec/rcov.opts ADDED
@@ -0,0 +1,3 @@
1
+ --exclude spec,gem
2
+ --text-summary
3
+ --sort coverage --sort-reverse
@@ -0,0 +1,67 @@
1
+ # encoding: UTF-8
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
4
+ require 'rspec'
5
+ require 'mysql2'
6
+ require 'timeout'
7
+
8
+ RSpec.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,54 @@
1
+ gem 'rake-compiler', '~> 0.7.1'
2
+ require "rake/extensiontask"
3
+
4
+ MYSQL_VERSION = "5.1.51"
5
+ MYSQL_MIRROR = ENV['MYSQL_MIRROR'] || "http://mysql.he.net/"
6
+
7
+ def gemspec
8
+ @clean_gemspec ||= eval(File.read(File.expand_path('../../mysql2.gemspec', __FILE__)))
9
+ end
10
+
11
+ Rake::ExtensionTask.new("mysql2", gemspec) do |ext|
12
+ # reference where the vendored MySQL got extracted
13
+ mysql_lib = File.expand_path(File.join(File.dirname(__FILE__), '..', 'vendor', "mysql-#{MYSQL_VERSION}-win32"))
14
+
15
+ # DRY options feed into compile or cross-compile process
16
+ windows_options = [
17
+ "--with-mysql-include=#{mysql_lib}/include",
18
+ "--with-mysql-lib=#{mysql_lib}/lib/opt"
19
+ ]
20
+
21
+ # automatically add build options to avoid need of manual input
22
+ if RUBY_PLATFORM =~ /mswin|mingw/ then
23
+ ext.config_options = windows_options
24
+ else
25
+ ext.cross_compile = true
26
+ ext.cross_platform = ['x86-mingw32', 'x86-mswin32-60']
27
+ ext.cross_config_options = windows_options
28
+
29
+ # inject 1.8/1.9 pure-ruby entry point when cross compiling only
30
+ ext.cross_compiling do |spec|
31
+ spec.files << 'lib/mysql2/mysql2.rb'
32
+ end
33
+ end
34
+
35
+ ext.lib_dir = File.join 'lib', 'mysql2'
36
+
37
+ # clean compiled extension
38
+ CLEAN.include "#{ext.lib_dir}/*.#{RbConfig::CONFIG['DLEXT']}"
39
+ end
40
+ Rake::Task[:spec].prerequisites << :compile
41
+
42
+ file 'lib/mysql2/mysql2.rb' do |t|
43
+ name = gemspec.name
44
+ File.open(t.name, 'wb') do |f|
45
+ f.write <<-eoruby
46
+ RUBY_VERSION =~ /(\\d+.\\d+)/
47
+ require "#{name}/\#{$1}/#{name}"
48
+ eoruby
49
+ end
50
+ end
51
+
52
+ if Rake::Task.task_defined?(:cross)
53
+ Rake::Task[:cross].prerequisites << "lib/mysql2/mysql2.rb"
54
+ end