mysql2 0.3.10 → 0.5.3

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