mysql2 0.3.18 → 0.4.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -0
- data/LICENSE +21 -0
- data/README.md +63 -12
- data/examples/eventmachine.rb +1 -1
- data/examples/threaded.rb +4 -6
- data/ext/mysql2/client.c +170 -175
- data/ext/mysql2/client.h +21 -1
- data/ext/mysql2/extconf.rb +95 -35
- data/ext/mysql2/infile.c +2 -2
- data/ext/mysql2/mysql2_ext.c +1 -0
- data/ext/mysql2/mysql2_ext.h +5 -6
- data/ext/mysql2/mysql_enc_name_to_ruby.h +2 -2
- data/ext/mysql2/mysql_enc_to_ruby.h +25 -22
- data/ext/mysql2/result.c +494 -132
- data/ext/mysql2/result.h +12 -6
- data/ext/mysql2/statement.c +494 -0
- data/ext/mysql2/statement.h +19 -0
- data/lib/mysql2/client.rb +68 -22
- data/lib/mysql2/console.rb +1 -1
- data/lib/mysql2/em.rb +5 -6
- data/lib/mysql2/error.rb +18 -27
- data/lib/mysql2/field.rb +3 -0
- data/lib/mysql2/statement.rb +17 -0
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +38 -18
- data/spec/em/em_spec.rb +21 -21
- data/spec/mysql2/client_spec.rb +393 -351
- data/spec/mysql2/error_spec.rb +37 -36
- data/spec/mysql2/result_spec.rb +213 -208
- data/spec/mysql2/statement_spec.rb +684 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/ssl/ca-cert.pem +17 -0
- data/spec/ssl/ca-key.pem +27 -0
- data/spec/ssl/ca.cnf +22 -0
- data/spec/ssl/cert.cnf +22 -0
- data/spec/ssl/client-cert.pem +17 -0
- data/spec/ssl/client-key.pem +27 -0
- data/spec/ssl/client-req.pem +15 -0
- data/spec/ssl/gen_certs.sh +48 -0
- data/spec/ssl/pkcs8-client-key.pem +28 -0
- data/spec/ssl/pkcs8-server-key.pem +28 -0
- data/spec/ssl/server-cert.pem +17 -0
- data/spec/ssl/server-key.pem +27 -0
- data/spec/ssl/server-req.pem +15 -0
- data/support/mysql_enc_to_ruby.rb +7 -8
- data/support/ruby_enc_to_mysql.rb +1 -1
- metadata +41 -46
data/lib/mysql2/em.rb
CHANGED
@@ -17,7 +17,7 @@ module Mysql2
|
|
17
17
|
detach
|
18
18
|
begin
|
19
19
|
result = @client.async_result
|
20
|
-
rescue
|
20
|
+
rescue => e
|
21
21
|
@deferable.fail(e)
|
22
22
|
else
|
23
23
|
@deferable.succeed(result)
|
@@ -34,17 +34,16 @@ module Mysql2
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def close(*args)
|
37
|
-
if @watch
|
38
|
-
|
39
|
-
end
|
37
|
+
@watch.detach if @watch && @watch.watching?
|
38
|
+
|
40
39
|
super(*args)
|
41
40
|
end
|
42
41
|
|
43
|
-
def query(sql, opts={})
|
42
|
+
def query(sql, opts = {})
|
44
43
|
if ::EM.reactor_running?
|
45
44
|
super(sql, opts.merge(:async => true))
|
46
45
|
deferable = ::EM::DefaultDeferrable.new
|
47
|
-
@watch = ::EM.watch(
|
46
|
+
@watch = ::EM.watch(socket, Watcher, self, deferable)
|
48
47
|
@watch.notify_readable = true
|
49
48
|
deferable
|
50
49
|
else
|
data/lib/mysql2/error.rb
CHANGED
@@ -2,25 +2,31 @@
|
|
2
2
|
|
3
3
|
module Mysql2
|
4
4
|
class Error < StandardError
|
5
|
-
|
6
|
-
|
5
|
+
ENCODE_OPTS = {
|
6
|
+
:undef => :replace,
|
7
|
+
:invalid => :replace,
|
8
|
+
:replace => '?'.freeze,
|
9
|
+
}.freeze
|
7
10
|
|
8
|
-
|
9
|
-
attr_reader :sql_state
|
10
|
-
attr_writer :server_version
|
11
|
+
attr_reader :error_number, :sql_state
|
11
12
|
|
12
13
|
# Mysql gem compatibility
|
13
14
|
alias_method :errno, :error_number
|
14
15
|
alias_method :error, :message
|
15
16
|
|
16
|
-
def initialize(msg
|
17
|
-
|
17
|
+
def initialize(msg)
|
18
|
+
@server_version ||= nil
|
18
19
|
|
19
20
|
super(clean_message(msg))
|
20
21
|
end
|
21
22
|
|
22
|
-
def sql_state
|
23
|
-
|
23
|
+
def self.new_with_args(msg, server_version, error_number, sql_state)
|
24
|
+
err = allocate
|
25
|
+
err.instance_variable_set('@server_version', server_version)
|
26
|
+
err.instance_variable_set('@error_number', error_number)
|
27
|
+
err.instance_variable_set('@sql_state', sql_state.respond_to?(:encode) ? sql_state.encode(ENCODE_OPTS) : sql_state)
|
28
|
+
err.send(:initialize, msg)
|
29
|
+
err
|
24
30
|
end
|
25
31
|
|
26
32
|
private
|
@@ -30,7 +36,7 @@ module Mysql2
|
|
30
36
|
# variable.
|
31
37
|
#
|
32
38
|
# See http://dev.mysql.com/doc/refman/5.5/en/charset-errors.html for
|
33
|
-
# more
|
39
|
+
# more context.
|
34
40
|
#
|
35
41
|
# Before MySQL 5.5 error message template strings are in whatever encoding
|
36
42
|
# is associated with the error message language.
|
@@ -53,27 +59,12 @@ module Mysql2
|
|
53
59
|
#
|
54
60
|
# Returns a valid UTF-8 string in Ruby 1.9+, the original string on Ruby 1.8
|
55
61
|
def clean_message(message)
|
56
|
-
return message
|
62
|
+
return message unless message.respond_to?(:encode)
|
57
63
|
|
58
64
|
if @server_version && @server_version > 50500
|
59
65
|
message.encode(ENCODE_OPTS)
|
60
66
|
else
|
61
|
-
|
62
|
-
message.scrub(REPLACEMENT_CHAR).encode(ENCODE_OPTS)
|
63
|
-
else
|
64
|
-
# This is ugly as hell but Ruby 1.9 doesn't provide a way to clean a string
|
65
|
-
# and retain it's valid UTF-8 characters, that I know of.
|
66
|
-
|
67
|
-
new_message = "".force_encoding(Encoding::UTF_8)
|
68
|
-
message.chars.each do |char|
|
69
|
-
if char.valid_encoding?
|
70
|
-
new_message << char
|
71
|
-
else
|
72
|
-
new_message << REPLACEMENT_CHAR
|
73
|
-
end
|
74
|
-
end
|
75
|
-
new_message.encode(ENCODE_OPTS)
|
76
|
-
end
|
67
|
+
message.encode(Encoding::UTF_8, ENCODE_OPTS)
|
77
68
|
end
|
78
69
|
end
|
79
70
|
end
|
data/lib/mysql2/field.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Mysql2
|
2
|
+
class Statement
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
if Thread.respond_to?(:handle_interrupt)
|
6
|
+
def execute(*args)
|
7
|
+
Thread.handle_interrupt(::Mysql2::Util::TimeoutError => :never) do
|
8
|
+
_execute(*args)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
else
|
12
|
+
def execute(*args)
|
13
|
+
_execute(*args)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/mysql2/version.rb
CHANGED
data/lib/mysql2.rb
CHANGED
@@ -8,16 +8,16 @@ require 'rational' unless RUBY_VERSION >= '1.9.2'
|
|
8
8
|
# Or to bomb out with a clear error message instead of a linker crash
|
9
9
|
if RUBY_PLATFORM =~ /mswin|mingw/
|
10
10
|
dll_path = if ENV['RUBY_MYSQL2_LIBMYSQL_DLL']
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
# If this environment variable is set, it overrides any other paths
|
12
|
+
# The user is advised to use backslashes not forward slashes
|
13
|
+
ENV['RUBY_MYSQL2_LIBMYSQL_DLL']
|
14
|
+
elsif File.exist?(File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)))
|
15
|
+
# Use vendor/libmysql.dll if it exists, convert slashes for Win32 LoadLibrary
|
16
|
+
File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)).tr('/', '\\')
|
17
|
+
else
|
18
|
+
# This will use default / system library paths
|
19
|
+
'libmysql.dll'
|
20
|
+
end
|
21
21
|
|
22
22
|
require 'Win32API'
|
23
23
|
LoadLibrary = Win32API.new('Kernel32', 'LoadLibrary', ['P'], 'I')
|
@@ -31,6 +31,8 @@ require 'mysql2/error'
|
|
31
31
|
require 'mysql2/mysql2'
|
32
32
|
require 'mysql2/result'
|
33
33
|
require 'mysql2/client'
|
34
|
+
require 'mysql2/field'
|
35
|
+
require 'mysql2/statement'
|
34
36
|
|
35
37
|
# = Mysql2
|
36
38
|
#
|
@@ -51,14 +53,32 @@ if defined?(ActiveRecord::VERSION::STRING) && ActiveRecord::VERSION::STRING < "3
|
|
51
53
|
end
|
52
54
|
|
53
55
|
# For holding utility methods
|
54
|
-
module Mysql2
|
56
|
+
module Mysql2
|
57
|
+
module Util
|
58
|
+
#
|
59
|
+
# Rekey a string-keyed hash with equivalent symbols.
|
60
|
+
#
|
61
|
+
def self.key_hash_as_symbols(hash)
|
62
|
+
return nil unless hash
|
63
|
+
Hash[hash.map { |k, v| [k.to_sym, v] }]
|
64
|
+
end
|
55
65
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
66
|
+
#
|
67
|
+
# In Mysql2::Client#query and Mysql2::Statement#execute,
|
68
|
+
# Thread#handle_interrupt is used to prevent Timeout#timeout
|
69
|
+
# from interrupting query execution.
|
70
|
+
#
|
71
|
+
# Timeout::ExitException was removed in Ruby 2.3.0, 2.2.3, and 2.1.8,
|
72
|
+
# but is present in earlier 2.1.x and 2.2.x, so we provide a shim.
|
73
|
+
#
|
74
|
+
if Thread.respond_to?(:handle_interrupt)
|
75
|
+
require 'timeout'
|
76
|
+
# rubocop:disable Style/ConstantName
|
77
|
+
TimeoutError = if defined?(::Timeout::ExitException)
|
78
|
+
::Timeout::ExitException
|
79
|
+
else
|
80
|
+
::Timeout::Error
|
81
|
+
end
|
82
|
+
end
|
62
83
|
end
|
63
|
-
|
64
84
|
end
|
data/spec/em/em_spec.rb
CHANGED
@@ -4,7 +4,7 @@ begin
|
|
4
4
|
require 'eventmachine'
|
5
5
|
require 'mysql2/em'
|
6
6
|
|
7
|
-
describe Mysql2::EM::Client do
|
7
|
+
RSpec.describe Mysql2::EM::Client do
|
8
8
|
it "should support async queries" do
|
9
9
|
results = []
|
10
10
|
EM.run do
|
@@ -24,8 +24,8 @@ begin
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
results[0].keys.
|
28
|
-
results[1].keys.
|
27
|
+
expect(results[0].keys).to include("second_query")
|
28
|
+
expect(results[1].keys).to include("first_query")
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should support queries in callbacks" do
|
@@ -44,38 +44,38 @@ begin
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
results[0].keys.
|
48
|
-
results[1].keys.
|
47
|
+
expect(results[0].keys).to include("first_query")
|
48
|
+
expect(results[1].keys).to include("second_query")
|
49
49
|
end
|
50
50
|
|
51
51
|
it "should not swallow exceptions raised in callbacks" do
|
52
|
-
|
52
|
+
expect {
|
53
53
|
EM.run do
|
54
54
|
client = Mysql2::EM::Client.new DatabaseCredentials['root']
|
55
55
|
defer = client.query "SELECT sleep(0.1) as first_query"
|
56
|
-
defer.callback do
|
56
|
+
defer.callback do
|
57
57
|
client.close
|
58
|
-
|
58
|
+
fail 'some error'
|
59
59
|
end
|
60
|
-
defer.errback do
|
60
|
+
defer.errback do
|
61
61
|
# This _shouldn't_ be run, but it needed to prevent the specs from
|
62
62
|
# freezing if this test fails.
|
63
63
|
EM.stop_event_loop
|
64
64
|
end
|
65
65
|
end
|
66
|
-
}.
|
66
|
+
}.to raise_error('some error')
|
67
67
|
end
|
68
68
|
|
69
69
|
context 'when an exception is raised by the client' do
|
70
70
|
let(:client) { Mysql2::EM::Client.new DatabaseCredentials['root'] }
|
71
71
|
let(:error) { StandardError.new('some error') }
|
72
|
-
before { client.
|
72
|
+
before { allow(client).to receive(:async_result).and_raise(error) }
|
73
73
|
|
74
74
|
it "should swallow exceptions raised in by the client" do
|
75
75
|
errors = []
|
76
76
|
EM.run do
|
77
77
|
defer = client.query "SELECT sleep(0.1) as first_query"
|
78
|
-
defer.callback do
|
78
|
+
defer.callback do
|
79
79
|
# This _shouldn't_ be run, but it is needed to prevent the specs from
|
80
80
|
# freezing if this test fails.
|
81
81
|
EM.stop_event_loop
|
@@ -85,7 +85,7 @@ begin
|
|
85
85
|
EM.stop_event_loop
|
86
86
|
end
|
87
87
|
end
|
88
|
-
errors.
|
88
|
+
expect(errors).to eq([error])
|
89
89
|
end
|
90
90
|
|
91
91
|
it "should fail the deferrable" do
|
@@ -93,19 +93,19 @@ begin
|
|
93
93
|
EM.run do
|
94
94
|
defer = client.query "SELECT sleep(0.025) as first_query"
|
95
95
|
EM.add_timer(0.1) do
|
96
|
-
defer.callback do
|
96
|
+
defer.callback do
|
97
97
|
callbacks_run << :callback
|
98
98
|
# This _shouldn't_ be run, but it is needed to prevent the specs from
|
99
99
|
# freezing if this test fails.
|
100
100
|
EM.stop_event_loop
|
101
101
|
end
|
102
|
-
defer.errback do
|
102
|
+
defer.errback do
|
103
103
|
callbacks_run << :errback
|
104
104
|
EM.stop_event_loop
|
105
105
|
end
|
106
106
|
end
|
107
107
|
end
|
108
|
-
callbacks_run.
|
108
|
+
expect(callbacks_run).to eq([:errback])
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
@@ -114,17 +114,17 @@ begin
|
|
114
114
|
EM.run do
|
115
115
|
client = Mysql2::EM::Client.new DatabaseCredentials['root']
|
116
116
|
defer = client.query("select sleep(0.025)")
|
117
|
-
defer.callback do
|
117
|
+
defer.callback do
|
118
118
|
callbacks_run << :callback
|
119
119
|
end
|
120
|
-
defer.errback do
|
120
|
+
defer.errback do
|
121
121
|
callbacks_run << :errback
|
122
122
|
end
|
123
123
|
EM.add_timer(0.1) do
|
124
|
-
callbacks_run.
|
125
|
-
|
124
|
+
expect(callbacks_run).to eq([:callback])
|
125
|
+
expect {
|
126
126
|
client.close
|
127
|
-
}.
|
127
|
+
}.not_to raise_error
|
128
128
|
EM.stop_event_loop
|
129
129
|
end
|
130
130
|
end
|