mysql2 0.4.0-x64-mingw32 → 0.4.1-x64-mingw32
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/examples/eventmachine.rb +1 -1
- data/ext/mysql2/client.c +45 -44
- data/ext/mysql2/client.h +1 -2
- data/ext/mysql2/extconf.rb +59 -37
- data/ext/mysql2/infile.c +2 -2
- data/ext/mysql2/mysql2_ext.h +4 -6
- data/ext/mysql2/mysql_enc_name_to_ruby.h +8 -8
- data/ext/mysql2/mysql_enc_to_ruby.h +25 -22
- data/ext/mysql2/result.c +4 -16
- data/ext/mysql2/result.h +3 -3
- data/ext/mysql2/statement.c +79 -42
- data/ext/mysql2/statement.h +2 -6
- data/lib/mysql2.rb +36 -18
- data/lib/mysql2/2.0/mysql2.so +0 -0
- data/lib/mysql2/2.1/mysql2.so +0 -0
- data/lib/mysql2/2.2/mysql2.so +0 -0
- data/lib/mysql2/client.rb +28 -27
- data/lib/mysql2/console.rb +1 -1
- data/lib/mysql2/em.rb +5 -6
- data/lib/mysql2/error.rb +10 -7
- data/lib/mysql2/field.rb +1 -2
- data/lib/mysql2/statement.rb +12 -0
- data/lib/mysql2/version.rb +1 -1
- data/spec/em/em_spec.rb +8 -8
- data/spec/mysql2/client_spec.rb +62 -37
- data/spec/mysql2/result_spec.rb +48 -48
- data/spec/mysql2/statement_spec.rb +143 -57
- 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 +28 -2
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')
|
@@ -53,14 +53,32 @@ if defined?(ActiveRecord::VERSION::STRING) && ActiveRecord::VERSION::STRING < "3
|
|
53
53
|
end
|
54
54
|
|
55
55
|
# For holding utility methods
|
56
|
-
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
|
57
65
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
64
83
|
end
|
65
|
-
|
66
84
|
end
|
data/lib/mysql2/2.0/mysql2.so
CHANGED
Binary file
|
data/lib/mysql2/2.1/mysql2.so
CHANGED
Binary file
|
data/lib/mysql2/2.2/mysql2.so
CHANGED
Binary file
|
data/lib/mysql2/client.rb
CHANGED
@@ -1,24 +1,27 @@
|
|
1
1
|
module Mysql2
|
2
2
|
class Client
|
3
3
|
attr_reader :query_options, :read_timeout
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
4
|
+
|
5
|
+
def self.default_query_options
|
6
|
+
@default_query_options ||= {
|
7
|
+
:as => :hash, # the type of object you want each row back as; also supports :array (an array of values)
|
8
|
+
:async => false, # don't wait for a result after sending the query, you'll have to monitor the socket yourself then eventually call Mysql2::Client#async_result
|
9
|
+
:cast_booleans => false, # cast tinyint(1) fields as true/false in ruby
|
10
|
+
:symbolize_keys => false, # return field names as symbols instead of strings
|
11
|
+
:database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in
|
12
|
+
:application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller
|
13
|
+
:cache_rows => true, # tells Mysql2 to use it's internal row cache for results
|
14
|
+
:connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION,
|
15
|
+
:cast => true,
|
16
|
+
:default_file => nil,
|
17
|
+
:default_group => nil,
|
18
|
+
}
|
19
|
+
end
|
17
20
|
|
18
21
|
def initialize(opts = {})
|
19
|
-
opts = Mysql2::Util.key_hash_as_symbols(
|
22
|
+
opts = Mysql2::Util.key_hash_as_symbols(opts)
|
20
23
|
@read_timeout = nil
|
21
|
-
@query_options =
|
24
|
+
@query_options = self.class.default_query_options.dup
|
22
25
|
@query_options.merge! opts
|
23
26
|
|
24
27
|
initialize_ext
|
@@ -26,11 +29,12 @@ module Mysql2
|
|
26
29
|
# Set default connect_timeout to avoid unlimited retries from signal interruption
|
27
30
|
opts[:connect_timeout] = 120 unless opts.key?(:connect_timeout)
|
28
31
|
|
32
|
+
# TODO: stricter validation rather than silent massaging
|
29
33
|
[:reconnect, :connect_timeout, :local_infile, :read_timeout, :write_timeout, :default_file, :default_group, :secure_auth, :init_command].each do |key|
|
30
34
|
next unless opts.key?(key)
|
31
35
|
case key
|
32
36
|
when :reconnect, :local_infile, :secure_auth
|
33
|
-
send(:"#{key}=", !!opts[key])
|
37
|
+
send(:"#{key}=", !!opts[key]) # rubocop:disable Style/DoubleNegation
|
34
38
|
when :connect_timeout, :read_timeout, :write_timeout
|
35
39
|
send(:"#{key}=", opts[key].to_i)
|
36
40
|
else
|
@@ -48,9 +52,9 @@ module Mysql2
|
|
48
52
|
flags = 0
|
49
53
|
flags |= @query_options[:connect_flags]
|
50
54
|
flags |= opts[:flags] if opts[:flags]
|
51
|
-
flags |= SSL_VERIFY_SERVER_CERT if opts[:sslverify]
|
55
|
+
flags |= SSL_VERIFY_SERVER_CERT if opts[:sslverify] && ssl_options.any?
|
52
56
|
|
53
|
-
if [:user
|
57
|
+
if [:user, :pass, :hostname, :dbname, :db, :sock].any? { |k| @query_options.key?(k) }
|
54
58
|
warn "============= WARNING FROM mysql2 ============="
|
55
59
|
warn "The options :user, :pass, :hostname, :dbname, :db, and :sock will be deprecated at some point in the future."
|
56
60
|
warn "Instead, please use :username, :password, :host, :port, :database, :socket, :flags for the options."
|
@@ -75,15 +79,9 @@ module Mysql2
|
|
75
79
|
connect user, pass, host, port, database, socket, flags
|
76
80
|
end
|
77
81
|
|
78
|
-
def self.default_query_options
|
79
|
-
@@default_query_options
|
80
|
-
end
|
81
|
-
|
82
82
|
if Thread.respond_to?(:handle_interrupt)
|
83
|
-
require 'timeout'
|
84
|
-
|
85
83
|
def query(sql, options = {})
|
86
|
-
Thread.handle_interrupt(::
|
84
|
+
Thread.handle_interrupt(::Mysql2::Util::TimeoutError => :never) do
|
87
85
|
_query(sql, @query_options.merge(options))
|
88
86
|
end
|
89
87
|
end
|
@@ -105,9 +103,12 @@ module Mysql2
|
|
105
103
|
self.class.info
|
106
104
|
end
|
107
105
|
|
108
|
-
|
109
|
-
|
106
|
+
class << self
|
107
|
+
private
|
108
|
+
|
109
|
+
def local_offset
|
110
110
|
::Time.local(2010).utc_offset.to_r / 86400
|
111
111
|
end
|
112
|
+
end
|
112
113
|
end
|
113
114
|
end
|
data/lib/mysql2/console.rb
CHANGED
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
@@ -8,22 +8,25 @@ module Mysql2
|
|
8
8
|
:replace => '?'.freeze,
|
9
9
|
}.freeze
|
10
10
|
|
11
|
-
|
12
|
-
attr_reader :sql_state
|
13
|
-
attr_writer :server_version
|
11
|
+
attr_reader :error_number, :sql_state
|
14
12
|
|
15
13
|
# Mysql gem compatibility
|
16
14
|
alias_method :errno, :error_number
|
17
15
|
alias_method :error, :message
|
18
16
|
|
19
|
-
def initialize(msg
|
20
|
-
|
17
|
+
def initialize(msg)
|
18
|
+
@server_version ||= nil
|
21
19
|
|
22
20
|
super(clean_message(msg))
|
23
21
|
end
|
24
22
|
|
25
|
-
def sql_state
|
26
|
-
|
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
|
27
30
|
end
|
28
31
|
|
29
32
|
private
|
data/lib/mysql2/field.rb
CHANGED
data/lib/mysql2/statement.rb
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
module Mysql2
|
2
2
|
class Statement
|
3
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
|
4
16
|
end
|
5
17
|
end
|
data/lib/mysql2/version.rb
CHANGED
data/spec/em/em_spec.rb
CHANGED
@@ -53,11 +53,11 @@ begin
|
|
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
|
@@ -75,7 +75,7 @@ begin
|
|
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
|
@@ -93,13 +93,13 @@ 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
|
@@ -114,10 +114,10 @@ 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
|
data/spec/mysql2/client_spec.rb
CHANGED
@@ -46,7 +46,7 @@ RSpec.describe Mysql2::Client do
|
|
46
46
|
it "should accept connect flags and pass them to #connect" do
|
47
47
|
klient = Class.new(Mysql2::Client) do
|
48
48
|
attr_reader :connect_args
|
49
|
-
def connect
|
49
|
+
def connect(*args)
|
50
50
|
@connect_args ||= []
|
51
51
|
@connect_args << args
|
52
52
|
end
|
@@ -58,7 +58,7 @@ RSpec.describe Mysql2::Client do
|
|
58
58
|
it "should default flags to (REMEMBER_OPTIONS, LONG_PASSWORD, LONG_FLAG, TRANSACTIONS, PROTOCOL_41, SECURE_CONNECTION)" do
|
59
59
|
klient = Class.new(Mysql2::Client) do
|
60
60
|
attr_reader :connect_args
|
61
|
-
def connect
|
61
|
+
def connect(*args)
|
62
62
|
@connect_args ||= []
|
63
63
|
@connect_args << args
|
64
64
|
end
|
@@ -117,32 +117,37 @@ RSpec.describe Mysql2::Client do
|
|
117
117
|
|
118
118
|
it "should be able to connect via SSL options" do
|
119
119
|
ssl = @client.query "SHOW VARIABLES LIKE 'have_ssl'"
|
120
|
-
ssl_uncompiled = ssl.any? {|x| x['Value'] == 'OFF'}
|
120
|
+
ssl_uncompiled = ssl.any? { |x| x['Value'] == 'OFF' }
|
121
121
|
pending("DON'T WORRY, THIS TEST PASSES - but SSL is not compiled into your MySQL daemon.") if ssl_uncompiled
|
122
|
-
ssl_disabled = ssl.any? {|x| x['Value'] == 'DISABLED'}
|
122
|
+
ssl_disabled = ssl.any? { |x| x['Value'] == 'DISABLED' }
|
123
123
|
pending("DON'T WORRY, THIS TEST PASSES - but SSL is not enabled in your MySQL daemon.") if ssl_disabled
|
124
124
|
|
125
125
|
# You may need to adjust the lines below to match your SSL certificate paths
|
126
126
|
ssl_client = nil
|
127
127
|
expect {
|
128
|
+
# rubocop:disable Style/TrailingComma
|
128
129
|
ssl_client = Mysql2::Client.new(
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
130
|
+
DatabaseCredentials['root'].merge(
|
131
|
+
'host' => 'mysql2gem.example.com', # must match the certificates
|
132
|
+
:sslkey => '/etc/mysql/client-key.pem',
|
133
|
+
:sslcert => '/etc/mysql/client-cert.pem',
|
134
|
+
:sslca => '/etc/mysql/ca-cert.pem',
|
135
|
+
:sslcipher => 'DHE-RSA-AES256-SHA',
|
136
|
+
:sslverify => true
|
137
|
+
)
|
134
138
|
)
|
139
|
+
# rubocop:enable Style/TrailingComma
|
135
140
|
}.not_to raise_error
|
136
141
|
|
137
142
|
results = ssl_client.query("SHOW STATUS WHERE Variable_name = \"Ssl_version\" OR Variable_name = \"Ssl_cipher\"").to_a
|
138
143
|
expect(results[0]['Variable_name']).to eql('Ssl_cipher')
|
139
144
|
expect(results[0]['Value']).not_to be_nil
|
140
|
-
expect(results[0]['Value']).to
|
145
|
+
expect(results[0]['Value']).to be_an_instance_of(String)
|
141
146
|
expect(results[0]['Value']).not_to be_empty
|
142
147
|
|
143
148
|
expect(results[1]['Variable_name']).to eql('Ssl_version')
|
144
149
|
expect(results[1]['Value']).not_to be_nil
|
145
|
-
expect(results[1]['Value']).to
|
150
|
+
expect(results[1]['Value']).to be_an_instance_of(String)
|
146
151
|
expect(results[1]['Value']).not_to be_empty
|
147
152
|
|
148
153
|
ssl_client.close
|
@@ -157,6 +162,14 @@ RSpec.describe Mysql2::Client do
|
|
157
162
|
sleep(0.5)
|
158
163
|
end
|
159
164
|
|
165
|
+
it "should terminate connections when calling close" do
|
166
|
+
expect {
|
167
|
+
Mysql2::Client.new(DatabaseCredentials['root']).close
|
168
|
+
}.to_not change {
|
169
|
+
@client.query("SHOW STATUS LIKE 'Aborted_clients'").first['Value'].to_i
|
170
|
+
}
|
171
|
+
end
|
172
|
+
|
160
173
|
it "should not leave dangling connections after garbage collection" do
|
161
174
|
run_gc
|
162
175
|
|
@@ -182,7 +195,7 @@ RSpec.describe Mysql2::Client do
|
|
182
195
|
|
183
196
|
# this empty `fork` call fixes this tests on RBX; without it, the next
|
184
197
|
# `fork` call hangs forever. WTF?
|
185
|
-
fork {
|
198
|
+
fork {}
|
186
199
|
|
187
200
|
fork do
|
188
201
|
client.query('SELECT 1')
|
@@ -264,7 +277,7 @@ RSpec.describe Mysql2::Client do
|
|
264
277
|
# # Note that mysql_info() returns a non-NULL value for INSERT ... VALUES only for the multiple-row form of the statement (that is, only if multiple value lists are specified).
|
265
278
|
@client.query("INSERT INTO infoTest (blah) VALUES (1234),(4535)")
|
266
279
|
|
267
|
-
expect(@client.query_info).to
|
280
|
+
expect(@client.query_info).to eql(:records => 2, :duplicates => 0, :warnings => 0)
|
268
281
|
expect(@client.query_info_string).to eq('Records: 2 Duplicates: 0 Warnings: 0')
|
269
282
|
|
270
283
|
@client.query "DROP TABLE infoTest"
|
@@ -276,7 +289,7 @@ RSpec.describe Mysql2::Client do
|
|
276
289
|
before(:all) do
|
277
290
|
@client_i = Mysql2::Client.new DatabaseCredentials['root'].merge(:local_infile => true)
|
278
291
|
local = @client_i.query "SHOW VARIABLES LIKE 'local_infile'"
|
279
|
-
local_enabled = local.any? {|x| x['Value'] == 'ON'}
|
292
|
+
local_enabled = local.any? { |x| x['Value'] == 'ON' }
|
280
293
|
pending("DON'T WORRY, THIS TEST PASSES - but LOCAL INFILE is not enabled in your MySQL daemon.") unless local_enabled
|
281
294
|
|
282
295
|
@client_i.query %[
|
@@ -308,10 +321,10 @@ RSpec.describe Mysql2::Client do
|
|
308
321
|
it "should LOAD DATA LOCAL INFILE" do
|
309
322
|
@client_i.query "LOAD DATA LOCAL INFILE 'spec/test_data' INTO TABLE infileTest"
|
310
323
|
info = @client_i.query_info
|
311
|
-
expect(info).to eql(
|
324
|
+
expect(info).to eql(:records => 1, :deleted => 0, :skipped => 0, :warnings => 0)
|
312
325
|
|
313
326
|
result = @client_i.query "SELECT * FROM infileTest"
|
314
|
-
expect(result.first).to eql(
|
327
|
+
expect(result.first).to eql('id' => 1, 'foo' => 'Hello', 'bar' => 'World')
|
315
328
|
end
|
316
329
|
end
|
317
330
|
|
@@ -379,16 +392,16 @@ RSpec.describe Mysql2::Client do
|
|
379
392
|
end
|
380
393
|
|
381
394
|
it "should return results as a hash by default" do
|
382
|
-
expect(@client.query("SELECT 1").first
|
395
|
+
expect(@client.query("SELECT 1").first).to be_an_instance_of(Hash)
|
383
396
|
end
|
384
397
|
|
385
398
|
it "should be able to return results as an array" do
|
386
|
-
expect(@client.query("SELECT 1", :as => :array).first
|
399
|
+
expect(@client.query("SELECT 1", :as => :array).first).to be_an_instance_of(Array)
|
387
400
|
@client.query("SELECT 1").each(:as => :array)
|
388
401
|
end
|
389
402
|
|
390
403
|
it "should be able to return results with symbolized keys" do
|
391
|
-
expect(@client.query("SELECT 1", :symbolize_keys => true).first.keys[0]
|
404
|
+
expect(@client.query("SELECT 1", :symbolize_keys => true).first.keys[0]).to be_an_instance_of(Symbol)
|
392
405
|
end
|
393
406
|
|
394
407
|
it "should require an open connection" do
|
@@ -451,7 +464,7 @@ RSpec.describe Mysql2::Client do
|
|
451
464
|
end
|
452
465
|
|
453
466
|
it "#socket should return a Fixnum (file descriptor from C)" do
|
454
|
-
expect(@client.socket
|
467
|
+
expect(@client.socket).to be_an_instance_of(Fixnum)
|
455
468
|
expect(@client.socket).not_to eql(0)
|
456
469
|
end
|
457
470
|
|
@@ -462,7 +475,7 @@ RSpec.describe Mysql2::Client do
|
|
462
475
|
}.to raise_error(Mysql2::Error)
|
463
476
|
end
|
464
477
|
|
465
|
-
it 'should be impervious to connection-corrupting timeouts ' do
|
478
|
+
it 'should be impervious to connection-corrupting timeouts in #query' do
|
466
479
|
pending('`Thread.handle_interrupt` is not defined') unless Thread.respond_to?(:handle_interrupt)
|
467
480
|
# attempt to break the connection
|
468
481
|
expect { Timeout.timeout(0.1) { @client.query('SELECT SLEEP(0.2)') } }.to raise_error(Timeout::Error)
|
@@ -471,6 +484,20 @@ RSpec.describe Mysql2::Client do
|
|
471
484
|
expect { @client.query('SELECT 1') }.to_not raise_error
|
472
485
|
end
|
473
486
|
|
487
|
+
it 'should be impervious to connection-corrupting timeouts in #execute' do
|
488
|
+
# the statement handle gets corrupted and will segfault the tests if interrupted,
|
489
|
+
# so we can't even use pending on this test, really have to skip it on older Rubies.
|
490
|
+
skip('`Thread.handle_interrupt` is not defined') unless Thread.respond_to?(:handle_interrupt)
|
491
|
+
|
492
|
+
# attempt to break the connection
|
493
|
+
stmt = @client.prepare('SELECT SLEEP(?)')
|
494
|
+
expect { Timeout.timeout(0.1) { stmt.execute(0.2) } }.to raise_error(Timeout::Error)
|
495
|
+
stmt.close
|
496
|
+
|
497
|
+
# expect the connection to not be broken
|
498
|
+
expect { @client.query('SELECT 1') }.to_not raise_error
|
499
|
+
end
|
500
|
+
|
474
501
|
context 'when a non-standard exception class is raised' do
|
475
502
|
it "should close the connection when an exception is raised" do
|
476
503
|
expect { Timeout.timeout(0.1, ArgumentError) { @client.query('SELECT SLEEP(1)') } }.to raise_error(ArgumentError)
|
@@ -542,7 +569,7 @@ RSpec.describe Mysql2::Client do
|
|
542
569
|
expect(loops >= 1).to be true
|
543
570
|
|
544
571
|
result = @client.async_result
|
545
|
-
expect(result
|
572
|
+
expect(result).to be_an_instance_of(Mysql2::Result)
|
546
573
|
end
|
547
574
|
end
|
548
575
|
|
@@ -561,21 +588,19 @@ RSpec.describe Mysql2::Client do
|
|
561
588
|
end
|
562
589
|
|
563
590
|
it "returns multiple result sets" do
|
564
|
-
expect(@multi_client.query("SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'").first).to eql(
|
591
|
+
expect(@multi_client.query("SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'").first).to eql('set_1' => 1)
|
565
592
|
|
566
593
|
expect(@multi_client.next_result).to be true
|
567
|
-
expect(@multi_client.store_result.first).to eql(
|
594
|
+
expect(@multi_client.store_result.first).to eql('set_2' => 2)
|
568
595
|
|
569
596
|
expect(@multi_client.next_result).to be false
|
570
597
|
end
|
571
598
|
|
572
599
|
it "does not interfere with other statements" do
|
573
600
|
@multi_client.query("SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'")
|
574
|
-
while
|
575
|
-
@multi_client.store_result
|
576
|
-
end
|
601
|
+
@multi_client.store_result while @multi_client.next_result
|
577
602
|
|
578
|
-
expect(@multi_client.query("SELECT 3 AS 'next'").first).to eq(
|
603
|
+
expect(@multi_client.query("SELECT 3 AS 'next'").first).to eq('next' => 3)
|
579
604
|
end
|
580
605
|
|
581
606
|
it "will raise on query if there are outstanding results to read" do
|
@@ -606,11 +631,11 @@ RSpec.describe Mysql2::Client do
|
|
606
631
|
it "#more_results? should work with stored procedures" do
|
607
632
|
@multi_client.query("DROP PROCEDURE IF EXISTS test_proc")
|
608
633
|
@multi_client.query("CREATE PROCEDURE test_proc() BEGIN SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'; END")
|
609
|
-
expect(@multi_client.query("CALL test_proc()").first).to eql(
|
634
|
+
expect(@multi_client.query("CALL test_proc()").first).to eql('set_1' => 1)
|
610
635
|
expect(@multi_client.more_results?).to be true
|
611
636
|
|
612
637
|
@multi_client.next_result
|
613
|
-
expect(@multi_client.store_result.first).to eql(
|
638
|
+
expect(@multi_client.store_result.first).to eql('set_2' => 2)
|
614
639
|
|
615
640
|
@multi_client.next_result
|
616
641
|
expect(@multi_client.store_result).to be_nil # this is the result from CALL itself
|
@@ -724,11 +749,11 @@ RSpec.describe Mysql2::Client do
|
|
724
749
|
|
725
750
|
it "#info should return a hash containing the client version ID and String" do
|
726
751
|
info = @client.info
|
727
|
-
expect(info
|
752
|
+
expect(info).to be_an_instance_of(Hash)
|
728
753
|
expect(info).to have_key(:id)
|
729
|
-
expect(info[:id]
|
754
|
+
expect(info[:id]).to be_an_instance_of(Fixnum)
|
730
755
|
expect(info).to have_key(:version)
|
731
|
-
expect(info[:version]
|
756
|
+
expect(info[:version]).to be_an_instance_of(String)
|
732
757
|
end
|
733
758
|
|
734
759
|
context "strings returned by #info" do
|
@@ -755,11 +780,11 @@ RSpec.describe Mysql2::Client do
|
|
755
780
|
|
756
781
|
it "#server_info should return a hash containing the client version ID and String" do
|
757
782
|
server_info = @client.server_info
|
758
|
-
expect(server_info
|
783
|
+
expect(server_info).to be_an_instance_of(Hash)
|
759
784
|
expect(server_info).to have_key(:id)
|
760
|
-
expect(server_info[:id]
|
785
|
+
expect(server_info[:id]).to be_an_instance_of(Fixnum)
|
761
786
|
expect(server_info).to have_key(:version)
|
762
|
-
expect(server_info[:version]
|
787
|
+
expect(server_info[:version]).to be_an_instance_of(String)
|
763
788
|
end
|
764
789
|
|
765
790
|
it "#server_info should require an open connection" do
|
@@ -848,7 +873,7 @@ RSpec.describe Mysql2::Client do
|
|
848
873
|
end
|
849
874
|
|
850
875
|
it "#thread_id should be a Fixnum" do
|
851
|
-
expect(@client.thread_id
|
876
|
+
expect(@client.thread_id).to be_an_instance_of(Fixnum)
|
852
877
|
end
|
853
878
|
|
854
879
|
it "should respond to #ping" do
|