mysql2 0.3.10 → 0.5.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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -230
  3. data/LICENSE +21 -0
  4. data/README.md +405 -80
  5. data/ext/mysql2/client.c +1110 -335
  6. data/ext/mysql2/client.h +18 -32
  7. data/ext/mysql2/extconf.rb +228 -37
  8. data/ext/mysql2/infile.c +122 -0
  9. data/ext/mysql2/infile.h +1 -0
  10. data/ext/mysql2/mysql2_ext.c +3 -1
  11. data/ext/mysql2/mysql2_ext.h +18 -16
  12. data/ext/mysql2/mysql_enc_name_to_ruby.h +172 -0
  13. data/ext/mysql2/mysql_enc_to_ruby.h +310 -0
  14. data/ext/mysql2/result.c +671 -226
  15. data/ext/mysql2/result.h +15 -6
  16. data/ext/mysql2/statement.c +604 -0
  17. data/ext/mysql2/statement.h +17 -0
  18. data/ext/mysql2/wait_for_single_fd.h +2 -1
  19. data/lib/mysql2/client.rb +125 -212
  20. data/lib/mysql2/console.rb +5 -0
  21. data/lib/mysql2/em.rb +24 -8
  22. data/lib/mysql2/error.rb +93 -8
  23. data/lib/mysql2/field.rb +3 -0
  24. data/lib/mysql2/result.rb +2 -0
  25. data/lib/mysql2/statement.rb +11 -0
  26. data/lib/mysql2/version.rb +1 -1
  27. data/lib/mysql2.rb +70 -5
  28. data/support/5072E1F5.asc +432 -0
  29. data/support/libmysql.def +219 -0
  30. data/support/mysql_enc_to_ruby.rb +86 -0
  31. data/support/ruby_enc_to_mysql.rb +63 -0
  32. metadata +45 -214
  33. data/.gitignore +0 -12
  34. data/.rspec +0 -3
  35. data/.rvmrc +0 -1
  36. data/.travis.yml +0 -7
  37. data/Gemfile +0 -3
  38. data/MIT-LICENSE +0 -20
  39. data/Rakefile +0 -5
  40. data/benchmark/active_record.rb +0 -51
  41. data/benchmark/active_record_threaded.rb +0 -42
  42. data/benchmark/allocations.rb +0 -33
  43. data/benchmark/escape.rb +0 -36
  44. data/benchmark/query_with_mysql_casting.rb +0 -80
  45. data/benchmark/query_without_mysql_casting.rb +0 -56
  46. data/benchmark/sequel.rb +0 -37
  47. data/benchmark/setup_db.rb +0 -119
  48. data/benchmark/threaded.rb +0 -44
  49. data/examples/eventmachine.rb +0 -21
  50. data/examples/threaded.rb +0 -20
  51. data/mysql2.gemspec +0 -29
  52. data/spec/em/em_spec.rb +0 -50
  53. data/spec/mysql2/client_spec.rb +0 -465
  54. data/spec/mysql2/error_spec.rb +0 -69
  55. data/spec/mysql2/result_spec.rb +0 -388
  56. data/spec/rcov.opts +0 -3
  57. data/spec/spec_helper.rb +0 -67
  58. data/tasks/benchmarks.rake +0 -20
  59. data/tasks/compile.rake +0 -71
  60. data/tasks/rspec.rake +0 -16
  61. data/tasks/vendor_mysql.rake +0 -40
@@ -1,465 +0,0 @@
1
- # encoding: UTF-8
2
- require 'spec_helper'
3
-
4
- describe Mysql2::Client do
5
- before(:each) do
6
- @client = Mysql2::Client.new
7
- end
8
-
9
- if defined? Encoding
10
- it "should raise an exception on create for invalid encodings" do
11
- lambda {
12
- c = Mysql2::Client.new(:encoding => "fake")
13
- }.should raise_error(Mysql2::Error)
14
- end
15
- end
16
-
17
- it "should accept connect flags and pass them to #connect" do
18
- klient = Class.new(Mysql2::Client) do
19
- attr_reader :connect_args
20
- def connect *args
21
- @connect_args ||= []
22
- @connect_args << args
23
- end
24
- end
25
- client = klient.new :flags => Mysql2::Client::FOUND_ROWS
26
- (client.connect_args.last.last & Mysql2::Client::FOUND_ROWS).should be_true
27
- end
28
-
29
- it "should default flags to (REMEMBER_OPTIONS, LONG_PASSWORD, LONG_FLAG, TRANSACTIONS, PROTOCOL_41, SECURE_CONNECTION)" do
30
- klient = Class.new(Mysql2::Client) do
31
- attr_reader :connect_args
32
- def connect *args
33
- @connect_args ||= []
34
- @connect_args << args
35
- end
36
- end
37
- client = klient.new
38
- (client.connect_args.last.last & (Mysql2::Client::REMEMBER_OPTIONS |
39
- Mysql2::Client::LONG_PASSWORD |
40
- Mysql2::Client::LONG_FLAG |
41
- Mysql2::Client::TRANSACTIONS |
42
- Mysql2::Client::PROTOCOL_41 |
43
- Mysql2::Client::SECURE_CONNECTION)).should be_true
44
- end
45
-
46
- it "should have a global default_query_options hash" do
47
- Mysql2::Client.should respond_to(:default_query_options)
48
- end
49
-
50
- it "should be able to connect via SSL options" do
51
- 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.")
52
- ssl_client = nil
53
- lambda {
54
- ssl_client = Mysql2::Client.new(
55
- :sslkey => '/path/to/client-key.pem',
56
- :sslcert => '/path/to/client-cert.pem',
57
- :sslca => '/path/to/ca-cert.pem',
58
- :sslcapath => '/path/to/newcerts/',
59
- :sslcipher => 'DHE-RSA-AES256-SHA'
60
- )
61
- }.should_not raise_error(Mysql2::Error)
62
-
63
- results = ssl_client.query("SHOW STATUS WHERE Variable_name = \"Ssl_version\" OR Variable_name = \"Ssl_cipher\"").to_a
64
- results[0]['Variable_name'].should eql('Ssl_cipher')
65
- results[0]['Value'].should_not be_nil
66
- results[0]['Value'].class.should eql(String)
67
-
68
- results[1]['Variable_name'].should eql('Ssl_version')
69
- results[1]['Value'].should_not be_nil
70
- results[1]['Value'].class.should eql(String)
71
- end
72
-
73
- it "should respond to #close" do
74
- @client.should respond_to(:close)
75
- end
76
-
77
- it "should be able to close properly" do
78
- @client.close.should be_nil
79
- lambda {
80
- @client.query "SELECT 1"
81
- }.should raise_error(Mysql2::Error)
82
- end
83
-
84
- it "should respond to #query" do
85
- @client.should respond_to(:query)
86
- end
87
-
88
- it "should expect read_timeout to be a positive integer" do
89
- lambda {
90
- Mysql2::Client.new(:read_timeout => -1)
91
- }.should raise_error(Mysql2::Error)
92
- end
93
-
94
- context "#query" do
95
- it "should only accept strings as the query parameter" do
96
- lambda {
97
- @client.query ["SELECT 'not right'"]
98
- }.should raise_error(TypeError)
99
- end
100
-
101
- it "should accept an options hash that inherits from Mysql2::Client.default_query_options" do
102
- @client.query "SELECT 1", :something => :else
103
- @client.query_options.should eql(@client.query_options.merge(:something => :else))
104
- end
105
-
106
- it "should return results as a hash by default" do
107
- @client.query("SELECT 1").first.class.should eql(Hash)
108
- end
109
-
110
- it "should be able to return results as an array" do
111
- @client.query("SELECT 1", :as => :array).first.class.should eql(Array)
112
- @client.query("SELECT 1").each(:as => :array)
113
- end
114
-
115
- it "should be able to return results with symbolized keys" do
116
- @client.query("SELECT 1", :symbolize_keys => true).first.keys[0].class.should eql(Symbol)
117
- end
118
-
119
- it "should require an open connection" do
120
- @client.close
121
- lambda {
122
- @client.query "SELECT 1"
123
- }.should raise_error(Mysql2::Error)
124
- end
125
-
126
- if RUBY_PLATFORM !~ /mingw|mswin/
127
- it "should not allow another query to be sent without fetching a result first" do
128
- @client.query("SELECT 1", :async => true)
129
- lambda {
130
- @client.query("SELECT 1")
131
- }.should raise_error(Mysql2::Error)
132
- end
133
-
134
- it "should timeout if we wait longer than :read_timeout" do
135
- client = Mysql2::Client.new(:read_timeout => 1)
136
- lambda {
137
- client.query("SELECT sleep(2)")
138
- }.should raise_error(Mysql2::Error)
139
- end
140
-
141
- # XXX this test is not deterministic (because Unix signal handling is not)
142
- # and may fail on a loaded system
143
- it "should run signal handlers while waiting for a response" do
144
- mark = {}
145
- trap(:USR1) { mark[:USR1] = Time.now }
146
- begin
147
- mark[:START] = Time.now
148
- pid = fork do
149
- sleep 1 # wait for client "SELECT sleep(2)" query to start
150
- Process.kill(:USR1, Process.ppid)
151
- sleep # wait for explicit kill to prevent GC disconnect
152
- end
153
- @client.query("SELECT sleep(2)")
154
- mark[:END] = Time.now
155
- mark.include?(:USR1).should be_true
156
- (mark[:USR1] - mark[:START]).should >= 1
157
- (mark[:USR1] - mark[:START]).should < 1.1
158
- (mark[:END] - mark[:USR1]).should > 0.9
159
- (mark[:END] - mark[:START]).should >= 2
160
- (mark[:END] - mark[:START]).should < 2.1
161
- Process.kill(:TERM, pid)
162
- Process.waitpid2(pid)
163
- ensure
164
- trap(:USR1, 'DEFAULT')
165
- end
166
- end
167
-
168
- it "#socket should return a Fixnum (file descriptor from C)" do
169
- @client.socket.class.should eql(Fixnum)
170
- @client.socket.should_not eql(0)
171
- end
172
-
173
- it "#socket should require an open connection" do
174
- @client.close
175
- lambda {
176
- @client.socket
177
- }.should raise_error(Mysql2::Error)
178
- end
179
-
180
- it "should close the connection when an exception is raised" do
181
- begin
182
- Timeout.timeout(1) do
183
- @client.query("SELECT sleep(2)")
184
- end
185
- rescue Timeout::Error
186
- end
187
-
188
- lambda {
189
- @client.query("SELECT 1")
190
- }.should raise_error(Mysql2::Error, 'closed MySQL connection')
191
- end
192
-
193
- it "should handle Timeouts without leaving the connection hanging if reconnect is true" do
194
- client = Mysql2::Client.new(:reconnect => true)
195
- begin
196
- Timeout.timeout(1) do
197
- client.query("SELECT sleep(2)")
198
- end
199
- rescue Timeout::Error
200
- end
201
-
202
- lambda {
203
- client.query("SELECT 1")
204
- }.should_not raise_error(Mysql2::Error)
205
- end
206
-
207
- it "threaded queries should be supported" do
208
- threads, results = [], {}
209
- connect = lambda{ Mysql2::Client.new(:host => "localhost", :username => "root") }
210
- Timeout.timeout(0.7) do
211
- 5.times {
212
- threads << Thread.new do
213
- results[Thread.current.object_id] = connect.call.query("SELECT sleep(0.5) as result")
214
- end
215
- }
216
- end
217
- threads.each{|t| t.join }
218
- results.keys.sort.should eql(threads.map{|t| t.object_id }.sort)
219
- end
220
-
221
- it "evented async queries should be supported" do
222
- # should immediately return nil
223
- @client.query("SELECT sleep(0.1)", :async => true).should eql(nil)
224
-
225
- io_wrapper = IO.for_fd(@client.socket)
226
- loops = 0
227
- loop do
228
- if IO.select([io_wrapper], nil, nil, 0.05)
229
- break
230
- else
231
- loops += 1
232
- end
233
- end
234
-
235
- # make sure we waited some period of time
236
- (loops >= 1).should be_true
237
-
238
- result = @client.async_result
239
- result.class.should eql(Mysql2::Result)
240
- end
241
- end
242
- end
243
-
244
- it "should respond to #socket" do
245
- @client.should respond_to(:socket)
246
- end
247
-
248
- if RUBY_PLATFORM =~ /mingw|mswin/
249
- it "#socket should raise as it's not supported" do
250
- lambda {
251
- @client.socket
252
- }.should raise_error(Mysql2::Error)
253
- end
254
- end
255
-
256
- it "should respond to escape" do
257
- Mysql2::Client.should respond_to(:escape)
258
- end
259
-
260
- context "escape" do
261
- it "should return a new SQL-escape version of the passed string" do
262
- Mysql2::Client.escape("abc'def\"ghi\0jkl%mno").should eql("abc\\'def\\\"ghi\\0jkl%mno")
263
- end
264
-
265
- it "should return the passed string if nothing was escaped" do
266
- str = "plain"
267
- Mysql2::Client.escape(str).object_id.should eql(str.object_id)
268
- end
269
-
270
- it "should not overflow the thread stack" do
271
- lambda {
272
- Thread.new { Mysql2::Client.escape("'" * 256 * 1024) }.join
273
- }.should_not raise_error(SystemStackError)
274
- end
275
-
276
- it "should not overflow the process stack" do
277
- lambda {
278
- Thread.new { Mysql2::Client.escape("'" * 1024 * 1024 * 4) }.join
279
- }.should_not raise_error(SystemStackError)
280
- end
281
-
282
- if RUBY_VERSION =~ /1.9/
283
- it "should carry over the original string's encoding" do
284
- str = "abc'def\"ghi\0jkl%mno"
285
- escaped = Mysql2::Client.escape(str)
286
- escaped.encoding.should eql(str.encoding)
287
-
288
- str.encode!('us-ascii')
289
- escaped = Mysql2::Client.escape(str)
290
- escaped.encoding.should eql(str.encoding)
291
- end
292
- end
293
- end
294
-
295
- it "should respond to #escape" do
296
- @client.should respond_to(:escape)
297
- end
298
-
299
- context "#escape" do
300
- it "should return a new SQL-escape version of the passed string" do
301
- @client.escape("abc'def\"ghi\0jkl%mno").should eql("abc\\'def\\\"ghi\\0jkl%mno")
302
- end
303
-
304
- it "should return the passed string if nothing was escaped" do
305
- str = "plain"
306
- @client.escape(str).object_id.should eql(str.object_id)
307
- end
308
-
309
- it "should not overflow the thread stack" do
310
- lambda {
311
- Thread.new { @client.escape("'" * 256 * 1024) }.join
312
- }.should_not raise_error(SystemStackError)
313
- end
314
-
315
- it "should not overflow the process stack" do
316
- lambda {
317
- Thread.new { @client.escape("'" * 1024 * 1024 * 4) }.join
318
- }.should_not raise_error(SystemStackError)
319
- end
320
-
321
- it "should require an open connection" do
322
- @client.close
323
- lambda {
324
- @client.escape ""
325
- }.should raise_error(Mysql2::Error)
326
- end
327
- end
328
-
329
- it "should respond to #info" do
330
- @client.should respond_to(:info)
331
- end
332
-
333
- it "#info should return a hash containing the client version ID and String" do
334
- info = @client.info
335
- info.class.should eql(Hash)
336
- info.should have_key(:id)
337
- info[:id].class.should eql(Fixnum)
338
- info.should have_key(:version)
339
- info[:version].class.should eql(String)
340
- end
341
-
342
- if defined? Encoding
343
- context "strings returned by #info" do
344
- it "should default to the connection's encoding if Encoding.default_internal is nil" do
345
- Encoding.default_internal = nil
346
- @client.info[:version].encoding.should eql(Encoding.find('utf-8'))
347
-
348
- client2 = Mysql2::Client.new :encoding => 'ascii'
349
- client2.info[:version].encoding.should eql(Encoding.find('us-ascii'))
350
- end
351
-
352
- it "should use Encoding.default_internal" do
353
- Encoding.default_internal = Encoding.find('utf-8')
354
- @client.info[:version].encoding.should eql(Encoding.default_internal)
355
- Encoding.default_internal = Encoding.find('us-ascii')
356
- @client.info[:version].encoding.should eql(Encoding.default_internal)
357
- end
358
- end
359
- end
360
-
361
- it "should respond to #server_info" do
362
- @client.should respond_to(:server_info)
363
- end
364
-
365
- it "#server_info should return a hash containing the client version ID and String" do
366
- server_info = @client.server_info
367
- server_info.class.should eql(Hash)
368
- server_info.should have_key(:id)
369
- server_info[:id].class.should eql(Fixnum)
370
- server_info.should have_key(:version)
371
- server_info[:version].class.should eql(String)
372
- end
373
-
374
- it "#server_info should require an open connection" do
375
- @client.close
376
- lambda {
377
- @client.server_info
378
- }.should raise_error(Mysql2::Error)
379
- end
380
-
381
- if defined? Encoding
382
- context "strings returned by #server_info" do
383
- it "should default to the connection's encoding if Encoding.default_internal is nil" do
384
- Encoding.default_internal = nil
385
- @client.server_info[:version].encoding.should eql(Encoding.find('utf-8'))
386
-
387
- client2 = Mysql2::Client.new :encoding => 'ascii'
388
- client2.server_info[:version].encoding.should eql(Encoding.find('us-ascii'))
389
- end
390
-
391
- it "should use Encoding.default_internal" do
392
- Encoding.default_internal = Encoding.find('utf-8')
393
- @client.server_info[:version].encoding.should eql(Encoding.default_internal)
394
- Encoding.default_internal = Encoding.find('us-ascii')
395
- @client.server_info[:version].encoding.should eql(Encoding.default_internal)
396
- end
397
- end
398
- end
399
-
400
- it "should raise a Mysql2::Error exception upon connection failure" do
401
- lambda {
402
- bad_client = Mysql2::Client.new :host => "localhost", :username => 'asdfasdf8d2h', :password => 'asdfasdfw42'
403
- }.should raise_error(Mysql2::Error)
404
-
405
- lambda {
406
- good_client = Mysql2::Client.new
407
- }.should_not raise_error(Mysql2::Error)
408
- end
409
-
410
- context 'write operations api' do
411
- before(:each) do
412
- @client.query "USE test"
413
- @client.query "CREATE TABLE IF NOT EXISTS lastIdTest (`id` int(11) NOT NULL AUTO_INCREMENT, blah INT(11), PRIMARY KEY (`id`))"
414
- end
415
-
416
- after(:each) do
417
- @client.query "DROP TABLE lastIdTest"
418
- end
419
-
420
- it "should respond to #last_id" do
421
- @client.should respond_to(:last_id)
422
- end
423
-
424
- it "#last_id should return a Fixnum, the from the last INSERT/UPDATE" do
425
- @client.last_id.should eql(0)
426
- @client.query "INSERT INTO lastIdTest (blah) VALUES (1234)"
427
- @client.last_id.should eql(1)
428
- end
429
-
430
- it "should respond to #last_id" do
431
- @client.should respond_to(:last_id)
432
- end
433
-
434
- it "#last_id should return a Fixnum, the from the last INSERT/UPDATE" do
435
- @client.query "INSERT INTO lastIdTest (blah) VALUES (1234)"
436
- @client.affected_rows.should eql(1)
437
- @client.query "UPDATE lastIdTest SET blah=4321 WHERE id=1"
438
- @client.affected_rows.should eql(1)
439
- end
440
- end
441
-
442
- it "should respond to #thread_id" do
443
- @client.should respond_to(:thread_id)
444
- end
445
-
446
- it "#thread_id should be a Fixnum" do
447
- @client.thread_id.class.should eql(Fixnum)
448
- end
449
-
450
- it "should respond to #ping" do
451
- @client.should respond_to(:ping)
452
- end
453
-
454
- it "#thread_id should return a boolean" do
455
- @client.ping.should eql(true)
456
- @client.close
457
- @client.ping.should eql(false)
458
- end
459
-
460
- if RUBY_VERSION =~ /1.9/
461
- it "should respond to #encoding" do
462
- @client.should respond_to(:encoding)
463
- end
464
- end
465
- end
@@ -1,69 +0,0 @@
1
- # encoding: UTF-8
2
- require 'spec_helper'
3
-
4
- describe Mysql2::Error do
5
- before(:each) do
6
- @client = Mysql2::Client.new :encoding => "utf8"
7
- begin
8
- @client.query("HAHAHA")
9
- rescue Mysql2::Error => e
10
- @error = e
11
- end
12
-
13
- @client2 = Mysql2::Client.new :encoding => "big5"
14
- begin
15
- @client2.query("HAHAHA")
16
- rescue Mysql2::Error => e
17
- @error2 = e
18
- end
19
- end
20
-
21
- it "should respond to #error_number" do
22
- @error.should respond_to(:error_number)
23
- end
24
-
25
- it "should respond to #sql_state" do
26
- @error.should respond_to(:sql_state)
27
- end
28
-
29
- # Mysql gem compatibility
30
- it "should alias #error_number to #errno" do
31
- @error.should respond_to(:errno)
32
- end
33
-
34
- it "should alias #message to #error" do
35
- @error.should respond_to(:error)
36
- end
37
-
38
- if RUBY_VERSION =~ /1.9/
39
- it "#message encoding should match the connection's encoding, or Encoding.default_internal if set" do
40
- if Encoding.default_internal.nil?
41
- @error.message.encoding.should eql(@client.encoding)
42
- @error2.message.encoding.should eql(@client2.encoding)
43
- else
44
- @error.message.encoding.should eql(Encoding.default_internal)
45
- @error2.message.encoding.should eql(Encoding.default_internal)
46
- end
47
- end
48
-
49
- it "#error encoding should match the connection's encoding, or Encoding.default_internal if set" do
50
- if Encoding.default_internal.nil?
51
- @error.error.encoding.should eql(@client.encoding)
52
- @error2.error.encoding.should eql(@client2.encoding)
53
- else
54
- @error.error.encoding.should eql(Encoding.default_internal)
55
- @error2.error.encoding.should eql(Encoding.default_internal)
56
- end
57
- end
58
-
59
- it "#sql_state encoding should match the connection's encoding, or Encoding.default_internal if set" do
60
- if Encoding.default_internal.nil?
61
- @error.sql_state.encoding.should eql(@client.encoding)
62
- @error2.sql_state.encoding.should eql(@client2.encoding)
63
- else
64
- @error.sql_state.encoding.should eql(Encoding.default_internal)
65
- @error2.sql_state.encoding.should eql(Encoding.default_internal)
66
- end
67
- end
68
- end
69
- end