mysql2 0.4.10 → 0.5.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.
- checksums.yaml +4 -4
- data/README.md +23 -6
- data/examples/eventmachine.rb +0 -2
- data/examples/threaded.rb +2 -4
- data/ext/mysql2/client.c +100 -51
- data/ext/mysql2/client.h +1 -39
- data/ext/mysql2/extconf.rb +23 -20
- data/ext/mysql2/mysql2_ext.c +2 -1
- data/ext/mysql2/mysql2_ext.h +8 -4
- data/ext/mysql2/result.c +15 -75
- data/ext/mysql2/result.h +2 -3
- data/ext/mysql2/statement.c +78 -71
- data/ext/mysql2/statement.h +0 -2
- data/ext/mysql2/wait_for_single_fd.h +2 -1
- data/lib/mysql2.rb +14 -15
- data/lib/mysql2/client.rb +33 -27
- data/lib/mysql2/em.rb +2 -4
- data/lib/mysql2/error.rb +49 -20
- data/lib/mysql2/result.rb +2 -0
- data/lib/mysql2/statement.rb +3 -9
- data/lib/mysql2/version.rb +1 -1
- data/spec/em/em_spec.rb +5 -6
- data/spec/mysql2/client_spec.rb +206 -173
- data/spec/mysql2/error_spec.rb +0 -4
- data/spec/mysql2/result_spec.rb +94 -154
- data/spec/mysql2/statement_spec.rb +105 -169
- data/spec/spec_helper.rb +6 -2
- data/support/mysql_enc_to_ruby.rb +2 -2
- data/support/ruby_enc_to_mysql.rb +5 -5
- metadata +6 -5
data/lib/mysql2/client.rb
CHANGED
@@ -4,22 +4,22 @@ module Mysql2
|
|
4
4
|
|
5
5
|
def self.default_query_options
|
6
6
|
@default_query_options ||= {
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
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 its internal row cache for results
|
14
|
+
connect_flags: REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION | CONNECT_ATTRS,
|
15
|
+
cast: true,
|
16
|
+
default_file: nil,
|
17
|
+
default_group: nil,
|
18
18
|
}
|
19
19
|
end
|
20
20
|
|
21
21
|
def initialize(opts = {})
|
22
|
-
|
22
|
+
raise Mysql2::Error, "Options parameter must be a Hash" unless opts.is_a? Hash
|
23
23
|
opts = Mysql2::Util.key_hash_as_symbols(opts)
|
24
24
|
@read_timeout = nil
|
25
25
|
@query_options = self.class.default_query_options.dup
|
@@ -31,7 +31,7 @@ module Mysql2
|
|
31
31
|
opts[:connect_timeout] = 120 unless opts.key?(:connect_timeout)
|
32
32
|
|
33
33
|
# TODO: stricter validation rather than silent massaging
|
34
|
-
[
|
34
|
+
%i[reconnect connect_timeout local_infile read_timeout write_timeout default_file default_group secure_auth init_command automatic_close enable_cleartext_plugin].each do |key|
|
35
35
|
next unless opts.key?(key)
|
36
36
|
case key
|
37
37
|
when :reconnect, :local_infile, :secure_auth, :automatic_close, :enable_cleartext_plugin
|
@@ -50,21 +50,21 @@ module Mysql2
|
|
50
50
|
ssl_set(*ssl_options) if ssl_options.any? || opts.key?(:sslverify)
|
51
51
|
self.ssl_mode = parse_ssl_mode(opts[:ssl_mode]) if opts[:ssl_mode]
|
52
52
|
|
53
|
-
case opts[:flags]
|
53
|
+
flags = case opts[:flags]
|
54
54
|
when Array
|
55
|
-
|
55
|
+
parse_flags_array(opts[:flags], @query_options[:connect_flags])
|
56
56
|
when String
|
57
|
-
|
57
|
+
parse_flags_array(opts[:flags].split(' '), @query_options[:connect_flags])
|
58
58
|
when Integer
|
59
|
-
|
59
|
+
@query_options[:connect_flags] | opts[:flags]
|
60
60
|
else
|
61
|
-
|
61
|
+
@query_options[:connect_flags]
|
62
62
|
end
|
63
63
|
|
64
64
|
# SSL verify is a connection flag rather than a mysql_ssl_set option
|
65
65
|
flags |= SSL_VERIFY_SERVER_CERT if opts[:sslverify]
|
66
66
|
|
67
|
-
if [
|
67
|
+
if %i[user pass hostname dbname db sock].any? { |k| @query_options.key?(k) }
|
68
68
|
warn "============= WARNING FROM mysql2 ============="
|
69
69
|
warn "The options :user, :pass, :hostname, :dbname, :db, and :sock are deprecated and will be removed at some point in the future."
|
70
70
|
warn "Instead, please use :username, :password, :host, :port, :database, :socket, :flags for the options."
|
@@ -85,8 +85,9 @@ module Mysql2
|
|
85
85
|
port = port.to_i unless port.nil?
|
86
86
|
database = database.to_s unless database.nil?
|
87
87
|
socket = socket.to_s unless socket.nil?
|
88
|
+
conn_attrs = parse_connect_attrs(opts[:connect_attrs])
|
88
89
|
|
89
|
-
connect user, pass, host, port, database, socket, flags
|
90
|
+
connect user, pass, host, port, database, socket, flags, conn_attrs
|
90
91
|
end
|
91
92
|
|
92
93
|
def parse_ssl_mode(mode)
|
@@ -114,14 +115,19 @@ module Mysql2
|
|
114
115
|
end
|
115
116
|
end
|
116
117
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
118
|
+
# Set default program_name in performance_schema.session_connect_attrs
|
119
|
+
# and performance_schema.session_account_connect_attrs
|
120
|
+
def parse_connect_attrs(conn_attrs)
|
121
|
+
return {} if Mysql2::Client::CONNECT_ATTRS.zero?
|
122
|
+
conn_attrs ||= {}
|
123
|
+
conn_attrs[:program_name] ||= $PROGRAM_NAME
|
124
|
+
conn_attrs.each_with_object({}) do |(key, value), hash|
|
125
|
+
hash[key.to_s] = value.to_s
|
122
126
|
end
|
123
|
-
|
124
|
-
|
127
|
+
end
|
128
|
+
|
129
|
+
def query(sql, options = {})
|
130
|
+
Thread.handle_interrupt(::Mysql2::Util::TIMEOUT_ERROR_CLASS => :never) do
|
125
131
|
_query(sql, @query_options.merge(options))
|
126
132
|
end
|
127
133
|
end
|
data/lib/mysql2/em.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
require 'eventmachine'
|
4
2
|
require 'mysql2'
|
5
3
|
|
@@ -17,7 +15,7 @@ module Mysql2
|
|
17
15
|
detach
|
18
16
|
begin
|
19
17
|
result = @client.async_result
|
20
|
-
rescue => e
|
18
|
+
rescue StandardError => e
|
21
19
|
@deferable.fail(e)
|
22
20
|
else
|
23
21
|
@deferable.succeed(result)
|
@@ -41,7 +39,7 @@ module Mysql2
|
|
41
39
|
|
42
40
|
def query(sql, opts = {})
|
43
41
|
if ::EM.reactor_running?
|
44
|
-
super(sql, opts.merge(:
|
42
|
+
super(sql, opts.merge(async: true))
|
45
43
|
deferable = ::EM::DefaultDeferrable.new
|
46
44
|
@watch = ::EM.watch(socket, Watcher, self, deferable)
|
47
45
|
@watch.notify_readable = true
|
data/lib/mysql2/error.rb
CHANGED
@@ -1,32 +1,65 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
1
|
module Mysql2
|
4
2
|
class Error < StandardError
|
5
3
|
ENCODE_OPTS = {
|
6
|
-
:
|
7
|
-
:
|
8
|
-
:
|
4
|
+
undef: :replace,
|
5
|
+
invalid: :replace,
|
6
|
+
replace: '?'.freeze,
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
ConnectionError = Class.new(Error)
|
10
|
+
TimeoutError = Class.new(Error)
|
11
|
+
|
12
|
+
CODES = {
|
13
|
+
1205 => TimeoutError, # ER_LOCK_WAIT_TIMEOUT
|
14
|
+
|
15
|
+
1044 => ConnectionError, # ER_DBACCESS_DENIED_ERROR
|
16
|
+
1045 => ConnectionError, # ER_ACCESS_DENIED_ERROR
|
17
|
+
1152 => ConnectionError, # ER_ABORTING_CONNECTION
|
18
|
+
1153 => ConnectionError, # ER_NET_PACKET_TOO_LARGE
|
19
|
+
1154 => ConnectionError, # ER_NET_READ_ERROR_FROM_PIPE
|
20
|
+
1155 => ConnectionError, # ER_NET_FCNTL_ERROR
|
21
|
+
1156 => ConnectionError, # ER_NET_PACKETS_OUT_OF_ORDER
|
22
|
+
1157 => ConnectionError, # ER_NET_UNCOMPRESS_ERROR
|
23
|
+
1158 => ConnectionError, # ER_NET_READ_ERROR
|
24
|
+
1159 => ConnectionError, # ER_NET_READ_INTERRUPTED
|
25
|
+
1160 => ConnectionError, # ER_NET_ERROR_ON_WRITE
|
26
|
+
1161 => ConnectionError, # ER_NET_WRITE_INTERRUPTED
|
27
|
+
|
28
|
+
2001 => ConnectionError, # CR_SOCKET_CREATE_ERROR
|
29
|
+
2002 => ConnectionError, # CR_CONNECTION_ERROR
|
30
|
+
2003 => ConnectionError, # CR_CONN_HOST_ERROR
|
31
|
+
2004 => ConnectionError, # CR_IPSOCK_ERROR
|
32
|
+
2005 => ConnectionError, # CR_UNKNOWN_HOST
|
33
|
+
2006 => ConnectionError, # CR_SERVER_GONE_ERROR
|
34
|
+
2007 => ConnectionError, # CR_VERSION_ERROR
|
35
|
+
2009 => ConnectionError, # CR_WRONG_HOST_INFO
|
36
|
+
2012 => ConnectionError, # CR_SERVER_HANDSHAKE_ERR
|
37
|
+
2013 => ConnectionError, # CR_SERVER_LOST
|
38
|
+
2020 => ConnectionError, # CR_NET_PACKET_TOO_LARGE
|
39
|
+
2026 => ConnectionError, # CR_SSL_CONNECTION_ERROR
|
40
|
+
2027 => ConnectionError, # CR_MALFORMED_PACKET
|
41
|
+
2047 => ConnectionError, # CR_CONN_UNKNOW_PROTOCOL
|
42
|
+
2048 => ConnectionError, # CR_INVALID_CONN_HANDLE
|
43
|
+
2049 => ConnectionError, # CR_UNUSED_1
|
9
44
|
}.freeze
|
10
45
|
|
11
46
|
attr_reader :error_number, :sql_state
|
12
47
|
|
13
48
|
# Mysql gem compatibility
|
14
|
-
|
15
|
-
|
49
|
+
alias errno error_number
|
50
|
+
alias error message
|
16
51
|
|
17
|
-
def initialize(msg)
|
18
|
-
@server_version
|
52
|
+
def initialize(msg, server_version = nil, error_number = nil, sql_state = nil)
|
53
|
+
@server_version = server_version
|
54
|
+
@error_number = error_number
|
55
|
+
@sql_state = sql_state ? sql_state.encode(ENCODE_OPTS) : nil
|
19
56
|
|
20
57
|
super(clean_message(msg))
|
21
58
|
end
|
22
59
|
|
23
60
|
def self.new_with_args(msg, server_version, error_number, sql_state)
|
24
|
-
|
25
|
-
|
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
|
61
|
+
error_class = CODES.fetch(error_number, self)
|
62
|
+
error_class.new(msg, server_version, error_number, sql_state)
|
30
63
|
end
|
31
64
|
|
32
65
|
private
|
@@ -55,12 +88,8 @@ module Mysql2
|
|
55
88
|
# encoding, we'll assume UTF-8 and clean the string of anything that's not a
|
56
89
|
# valid UTF-8 character.
|
57
90
|
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
# Returns a valid UTF-8 string in Ruby 1.9+, the original string on Ruby 1.8
|
91
|
+
# Returns a valid UTF-8 string.
|
61
92
|
def clean_message(message)
|
62
|
-
return message unless message.respond_to?(:encode)
|
63
|
-
|
64
93
|
if @server_version && @server_version > 50500
|
65
94
|
message.encode(ENCODE_OPTS)
|
66
95
|
else
|
data/lib/mysql2/result.rb
CHANGED
data/lib/mysql2/statement.rb
CHANGED
@@ -2,15 +2,9 @@ module Mysql2
|
|
2
2
|
class Statement
|
3
3
|
include Enumerable
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
_execute(*args)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
else
|
12
|
-
def execute(*args)
|
13
|
-
_execute(*args)
|
5
|
+
def execute(*args, **kwargs)
|
6
|
+
Thread.handle_interrupt(::Mysql2::Util::TIMEOUT_ERROR_CLASS => :never) do
|
7
|
+
_execute(*args, **kwargs)
|
14
8
|
end
|
15
9
|
end
|
16
10
|
end
|
data/lib/mysql2/version.rb
CHANGED
data/spec/em/em_spec.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
require 'spec_helper'
|
3
2
|
begin
|
4
3
|
require 'eventmachine'
|
@@ -49,13 +48,13 @@ begin
|
|
49
48
|
end
|
50
49
|
|
51
50
|
it "should not swallow exceptions raised in callbacks" do
|
52
|
-
expect
|
51
|
+
expect do
|
53
52
|
EM.run do
|
54
53
|
client = Mysql2::EM::Client.new DatabaseCredentials['root']
|
55
54
|
defer = client.query "SELECT sleep(0.1) as first_query"
|
56
55
|
defer.callback do
|
57
56
|
client.close
|
58
|
-
|
57
|
+
raise 'some error'
|
59
58
|
end
|
60
59
|
defer.errback do
|
61
60
|
# This _shouldn't_ be run, but it needed to prevent the specs from
|
@@ -63,7 +62,7 @@ begin
|
|
63
62
|
EM.stop_event_loop
|
64
63
|
end
|
65
64
|
end
|
66
|
-
|
65
|
+
end.to raise_error('some error')
|
67
66
|
end
|
68
67
|
|
69
68
|
context 'when an exception is raised by the client' do
|
@@ -123,9 +122,9 @@ begin
|
|
123
122
|
end
|
124
123
|
EM.add_timer(0.1) do
|
125
124
|
expect(callbacks_run).to eq([:callback])
|
126
|
-
expect
|
125
|
+
expect do
|
127
126
|
client.close
|
128
|
-
|
127
|
+
end.not_to raise_error
|
129
128
|
EM.stop_event_loop
|
130
129
|
end
|
131
130
|
end
|
data/spec/mysql2/client_spec.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
require 'spec_helper'
|
3
2
|
|
4
3
|
RSpec.describe Mysql2::Client do
|
@@ -6,46 +5,46 @@ RSpec.describe Mysql2::Client do
|
|
6
5
|
let(:cnf_file) { File.expand_path('../../my.cnf', __FILE__) }
|
7
6
|
|
8
7
|
it "should not raise an exception for valid defaults group" do
|
9
|
-
expect
|
10
|
-
new_client(:
|
11
|
-
|
8
|
+
expect do
|
9
|
+
new_client(default_file: cnf_file, default_group: "test")
|
10
|
+
end.not_to raise_error
|
12
11
|
end
|
13
12
|
|
14
13
|
it "should not raise an exception without default group" do
|
15
|
-
expect
|
16
|
-
new_client(:
|
17
|
-
|
14
|
+
expect do
|
15
|
+
new_client(default_file: cnf_file)
|
16
|
+
end.not_to raise_error
|
18
17
|
end
|
19
18
|
end
|
20
19
|
|
21
|
-
it "should raise
|
22
|
-
expect
|
20
|
+
it "should raise a Mysql::Error::ConnectionError upon connection failure" do
|
21
|
+
expect do
|
23
22
|
# The odd local host IP address forces the mysql client library to
|
24
23
|
# use a TCP socket rather than a domain socket.
|
25
24
|
new_client('host' => '127.0.0.2', 'port' => 999999)
|
26
|
-
|
25
|
+
end.to raise_error(Mysql2::Error::ConnectionError)
|
27
26
|
end
|
28
27
|
|
29
28
|
it "should raise an exception on create for invalid encodings" do
|
30
|
-
expect
|
31
|
-
new_client(:
|
32
|
-
|
29
|
+
expect do
|
30
|
+
new_client(encoding: "fake")
|
31
|
+
end.to raise_error(Mysql2::Error)
|
33
32
|
end
|
34
33
|
|
35
34
|
it "should raise an exception on non-string encodings" do
|
36
|
-
expect
|
37
|
-
new_client(:
|
38
|
-
|
35
|
+
expect do
|
36
|
+
new_client(encoding: :fake)
|
37
|
+
end.to raise_error(TypeError)
|
39
38
|
end
|
40
39
|
|
41
40
|
it "should not raise an exception on create for a valid encoding" do
|
42
|
-
expect
|
43
|
-
new_client(:
|
44
|
-
|
41
|
+
expect do
|
42
|
+
new_client(encoding: "utf8")
|
43
|
+
end.not_to raise_error
|
45
44
|
|
46
|
-
expect
|
47
|
-
new_client(DatabaseCredentials['root'].merge(:
|
48
|
-
|
45
|
+
expect do
|
46
|
+
new_client(DatabaseCredentials['root'].merge(encoding: "big5"))
|
47
|
+
end.not_to raise_error
|
49
48
|
end
|
50
49
|
|
51
50
|
Klient = Class.new(Mysql2::Client) do
|
@@ -57,18 +56,18 @@ RSpec.describe Mysql2::Client do
|
|
57
56
|
end
|
58
57
|
|
59
58
|
it "should accept connect flags and pass them to #connect" do
|
60
|
-
client = Klient.new :
|
59
|
+
client = Klient.new flags: Mysql2::Client::FOUND_ROWS
|
61
60
|
expect(client.connect_args.last[6] & Mysql2::Client::FOUND_ROWS).to be > 0
|
62
61
|
end
|
63
62
|
|
64
63
|
it "should parse flags array" do
|
65
|
-
client = Klient.new :
|
64
|
+
client = Klient.new flags: %w[FOUND_ROWS -PROTOCOL_41]
|
66
65
|
expect(client.connect_args.last[6] & Mysql2::Client::FOUND_ROWS).to eql(Mysql2::Client::FOUND_ROWS)
|
67
66
|
expect(client.connect_args.last[6] & Mysql2::Client::PROTOCOL_41).to eql(0)
|
68
67
|
end
|
69
68
|
|
70
69
|
it "should parse flags string" do
|
71
|
-
client = Klient.new :
|
70
|
+
client = Klient.new flags: "FOUND_ROWS -PROTOCOL_41"
|
72
71
|
expect(client.connect_args.last[6] & Mysql2::Client::FOUND_ROWS).to eql(Mysql2::Client::FOUND_ROWS)
|
73
72
|
expect(client.connect_args.last[6] & Mysql2::Client::PROTOCOL_41).to eql(0)
|
74
73
|
end
|
@@ -80,7 +79,8 @@ RSpec.describe Mysql2::Client do
|
|
80
79
|
Mysql2::Client::LONG_FLAG |
|
81
80
|
Mysql2::Client::TRANSACTIONS |
|
82
81
|
Mysql2::Client::PROTOCOL_41 |
|
83
|
-
Mysql2::Client::SECURE_CONNECTION
|
82
|
+
Mysql2::Client::SECURE_CONNECTION |
|
83
|
+
Mysql2::Client::CONNECT_ATTRS
|
84
84
|
expect(client.connect_args.last[6]).to eql(client_flags)
|
85
85
|
end
|
86
86
|
|
@@ -135,18 +135,16 @@ RSpec.describe Mysql2::Client do
|
|
135
135
|
|
136
136
|
# You may need to adjust the lines below to match your SSL certificate paths
|
137
137
|
ssl_client = nil
|
138
|
-
expect
|
139
|
-
# rubocop:disable Style/TrailingComma
|
138
|
+
expect do
|
140
139
|
ssl_client = new_client(
|
141
140
|
'host' => 'mysql2gem.example.com', # must match the certificates
|
142
141
|
:sslkey => '/etc/mysql/client-key.pem',
|
143
142
|
:sslcert => '/etc/mysql/client-cert.pem',
|
144
143
|
:sslca => '/etc/mysql/ca-cert.pem',
|
145
144
|
:sslcipher => 'DHE-RSA-AES256-SHA',
|
146
|
-
:sslverify => true
|
145
|
+
:sslverify => true,
|
147
146
|
)
|
148
|
-
|
149
|
-
}.not_to raise_error
|
147
|
+
end.not_to raise_error
|
150
148
|
|
151
149
|
results = Hash[ssl_client.query('SHOW STATUS WHERE Variable_name LIKE "Ssl_%"').map { |x| x.values_at('Variable_name', 'Value') }]
|
152
150
|
expect(results['Ssl_cipher']).not_to be_empty
|
@@ -166,7 +164,8 @@ RSpec.describe Mysql2::Client do
|
|
166
164
|
end
|
167
165
|
|
168
166
|
it "should terminate connections when calling close" do
|
169
|
-
|
167
|
+
# rubocop:disable Lint/AmbiguousBlockAssociation
|
168
|
+
expect do
|
170
169
|
client = Mysql2::Client.new(DatabaseCredentials['root'])
|
171
170
|
connection_id = client.thread_id
|
172
171
|
client.close
|
@@ -180,27 +179,64 @@ RSpec.describe Mysql2::Client do
|
|
180
179
|
sleep(0.1)
|
181
180
|
end
|
182
181
|
expect(closed).to eq(true)
|
183
|
-
|
182
|
+
end.to_not change {
|
184
183
|
@client.query("SHOW STATUS LIKE 'Aborted_%'").to_a
|
185
184
|
}
|
185
|
+
# rubocop:enable Lint/AmbiguousBlockAssociation
|
186
186
|
end
|
187
187
|
|
188
188
|
it "should not leave dangling connections after garbage collection" do
|
189
189
|
run_gc
|
190
|
-
|
191
|
-
|
190
|
+
# rubocop:disable Lint/AmbiguousBlockAssociation
|
191
|
+
expect do
|
192
|
+
expect do
|
192
193
|
10.times do
|
193
194
|
Mysql2::Client.new(DatabaseCredentials['root']).query('SELECT 1')
|
194
195
|
end
|
195
|
-
|
196
|
+
end.to change {
|
196
197
|
@client.query("SHOW STATUS LIKE 'Threads_connected'").first['Value'].to_i
|
197
198
|
}.by(10)
|
198
199
|
|
199
200
|
run_gc
|
200
|
-
|
201
|
+
end.to_not change {
|
201
202
|
@client.query("SHOW STATUS LIKE 'Aborted_%'").to_a +
|
202
203
|
@client.query("SHOW STATUS LIKE 'Threads_connected'").to_a
|
203
204
|
}
|
205
|
+
# rubocop:enable Lint/AmbiguousBlockAssociation
|
206
|
+
end
|
207
|
+
|
208
|
+
context "#set_server_option" do
|
209
|
+
let(:client) do
|
210
|
+
new_client.tap do |client|
|
211
|
+
client.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'returns true when multi_statements is enable' do
|
216
|
+
expect(client.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)).to be true
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'returns true when multi_statements is disable' do
|
220
|
+
expect(client.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)).to be true
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'returns false when multi_statements is neither OPTION_MULTI_STATEMENTS_OFF or OPTION_MULTI_STATEMENTS_ON' do
|
224
|
+
expect(client.set_server_option(344)).to be false
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'enables multiple-statement' do
|
228
|
+
client.query("SELECT 1;SELECT 2;")
|
229
|
+
|
230
|
+
expect(client.next_result).to be true
|
231
|
+
expect(client.store_result.first).to eql('2' => 2)
|
232
|
+
expect(client.next_result).to be false
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'disables multiple-statement' do
|
236
|
+
client.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
|
237
|
+
|
238
|
+
expect { client.query("SELECT 1;SELECT 2;") }.to raise_error(Mysql2::Error)
|
239
|
+
end
|
204
240
|
end
|
205
241
|
|
206
242
|
context "#automatic_close" do
|
@@ -211,24 +247,24 @@ RSpec.describe Mysql2::Client do
|
|
211
247
|
if RUBY_PLATFORM =~ /mingw|mswin/
|
212
248
|
it "cannot be disabled" do
|
213
249
|
expect do
|
214
|
-
client = new_client(:
|
250
|
+
client = new_client(automatic_close: false)
|
215
251
|
expect(client.automatic_close?).to be(true)
|
216
252
|
end.to output(/always closed by garbage collector/).to_stderr
|
217
253
|
|
218
254
|
expect do
|
219
|
-
client = new_client(:
|
255
|
+
client = new_client(automatic_close: true)
|
220
256
|
expect(client.automatic_close?).to be(true)
|
221
257
|
end.to_not output(/always closed by garbage collector/).to_stderr
|
222
258
|
|
223
259
|
expect do
|
224
|
-
client = new_client(:
|
260
|
+
client = new_client(automatic_close: true)
|
225
261
|
client.automatic_close = false
|
226
262
|
expect(client.automatic_close?).to be(true)
|
227
263
|
end.to output(/always closed by garbage collector/).to_stderr
|
228
264
|
end
|
229
265
|
else
|
230
266
|
it "can be configured" do
|
231
|
-
client = new_client(:
|
267
|
+
client = new_client(automatic_close: false)
|
232
268
|
expect(client.automatic_close?).to be(false)
|
233
269
|
end
|
234
270
|
|
@@ -272,9 +308,9 @@ RSpec.describe Mysql2::Client do
|
|
272
308
|
database = 1235
|
273
309
|
@client.query "CREATE DATABASE IF NOT EXISTS `#{database}`"
|
274
310
|
|
275
|
-
expect
|
311
|
+
expect do
|
276
312
|
new_client('database' => database)
|
277
|
-
|
313
|
+
end.not_to raise_error
|
278
314
|
|
279
315
|
@client.query "DROP DATABASE IF EXISTS `#{database}`"
|
280
316
|
end
|
@@ -285,9 +321,9 @@ RSpec.describe Mysql2::Client do
|
|
285
321
|
|
286
322
|
it "should be able to close properly" do
|
287
323
|
expect(@client.close).to be_nil
|
288
|
-
expect
|
324
|
+
expect do
|
289
325
|
@client.query "SELECT 1"
|
290
|
-
|
326
|
+
end.to raise_error(Mysql2::Error)
|
291
327
|
end
|
292
328
|
|
293
329
|
context "#closed?" do
|
@@ -302,11 +338,11 @@ RSpec.describe Mysql2::Client do
|
|
302
338
|
end
|
303
339
|
|
304
340
|
it "should not try to query closed mysql connection" do
|
305
|
-
client = new_client(:
|
341
|
+
client = new_client(reconnect: true)
|
306
342
|
expect(client.close).to be_nil
|
307
|
-
expect
|
343
|
+
expect do
|
308
344
|
client.query "SELECT 1"
|
309
|
-
|
345
|
+
end.to raise_error(Mysql2::Error)
|
310
346
|
end
|
311
347
|
|
312
348
|
it "should respond to #query" do
|
@@ -355,7 +391,7 @@ RSpec.describe Mysql2::Client do
|
|
355
391
|
# # 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).
|
356
392
|
@client.query("INSERT INTO infoTest (blah) VALUES (1234),(4535)")
|
357
393
|
|
358
|
-
expect(@client.query_info).to eql(:
|
394
|
+
expect(@client.query_info).to eql(records: 2, duplicates: 0, warnings: 0)
|
359
395
|
expect(@client.query_info_string).to eq('Records: 2 Duplicates: 0 Warnings: 0')
|
360
396
|
|
361
397
|
@client.query "DROP TABLE infoTest"
|
@@ -365,7 +401,7 @@ RSpec.describe Mysql2::Client do
|
|
365
401
|
|
366
402
|
context ":local_infile" do
|
367
403
|
before(:all) do
|
368
|
-
new_client(:
|
404
|
+
new_client(local_infile: true) do |client|
|
369
405
|
local = client.query "SHOW VARIABLES LIKE 'local_infile'"
|
370
406
|
local_enabled = local.any? { |x| x['Value'] == 'ON' }
|
371
407
|
skip("DON'T WORRY, THIS TEST PASSES - but LOCAL INFILE is not enabled in your MySQL daemon.") unless local_enabled
|
@@ -387,24 +423,24 @@ RSpec.describe Mysql2::Client do
|
|
387
423
|
end
|
388
424
|
|
389
425
|
it "should raise an error when local_infile is disabled" do
|
390
|
-
client = new_client(:
|
391
|
-
expect
|
426
|
+
client = new_client(local_infile: false)
|
427
|
+
expect do
|
392
428
|
client.query "LOAD DATA LOCAL INFILE 'spec/test_data' INTO TABLE infileTest"
|
393
|
-
|
429
|
+
end.to raise_error(Mysql2::Error, /command is not allowed/)
|
394
430
|
end
|
395
431
|
|
396
432
|
it "should raise an error when a non-existent file is loaded" do
|
397
|
-
client = new_client(:
|
398
|
-
expect
|
433
|
+
client = new_client(local_infile: true)
|
434
|
+
expect do
|
399
435
|
client.query "LOAD DATA LOCAL INFILE 'this/file/is/not/here' INTO TABLE infileTest"
|
400
|
-
|
436
|
+
end.to raise_error(Mysql2::Error, 'No such file or directory: this/file/is/not/here')
|
401
437
|
end
|
402
438
|
|
403
439
|
it "should LOAD DATA LOCAL INFILE" do
|
404
|
-
client = new_client(:
|
440
|
+
client = new_client(local_infile: true)
|
405
441
|
client.query "LOAD DATA LOCAL INFILE 'spec/test_data' INTO TABLE infileTest"
|
406
442
|
info = client.query_info
|
407
|
-
expect(info).to eql(:
|
443
|
+
expect(info).to eql(records: 1, deleted: 0, skipped: 0, warnings: 0)
|
408
444
|
|
409
445
|
result = client.query "SELECT * FROM infileTest"
|
410
446
|
expect(result.first).to eql('id' => 1, 'foo' => 'Hello', 'bar' => 'World')
|
@@ -412,57 +448,77 @@ RSpec.describe Mysql2::Client do
|
|
412
448
|
end
|
413
449
|
|
414
450
|
it "should expect connect_timeout to be a positive integer" do
|
415
|
-
expect
|
416
|
-
new_client(:
|
417
|
-
|
451
|
+
expect do
|
452
|
+
new_client(connect_timeout: -1)
|
453
|
+
end.to raise_error(Mysql2::Error)
|
418
454
|
end
|
419
455
|
|
420
456
|
it "should expect read_timeout to be a positive integer" do
|
421
|
-
expect
|
422
|
-
new_client(:
|
423
|
-
|
457
|
+
expect do
|
458
|
+
new_client(read_timeout: -1)
|
459
|
+
end.to raise_error(Mysql2::Error)
|
424
460
|
end
|
425
461
|
|
426
462
|
it "should expect write_timeout to be a positive integer" do
|
427
|
-
expect
|
428
|
-
new_client(:
|
429
|
-
|
463
|
+
expect do
|
464
|
+
new_client(write_timeout: -1)
|
465
|
+
end.to raise_error(Mysql2::Error)
|
430
466
|
end
|
431
467
|
|
432
468
|
it "should allow nil read_timeout" do
|
433
|
-
client = new_client(:
|
469
|
+
client = new_client(read_timeout: nil)
|
434
470
|
|
435
471
|
expect(client.read_timeout).to be_nil
|
436
472
|
end
|
437
473
|
|
474
|
+
it "should set default program_name in connect_attrs" do
|
475
|
+
client = new_client
|
476
|
+
if Mysql2::Client::CONNECT_ATTRS.zero? || client.server_info[:version].match(/10.[01].\d+-MariaDB/)
|
477
|
+
pending('Both client and server versions must be MySQL 5.6 or MariaDB 10.2 or later.')
|
478
|
+
end
|
479
|
+
result = client.query("SELECT attr_value FROM performance_schema.session_account_connect_attrs WHERE processlist_id = connection_id() AND attr_name = 'program_name'")
|
480
|
+
expect(result.first['attr_value']).to eq($PROGRAM_NAME)
|
481
|
+
end
|
482
|
+
|
483
|
+
it "should set custom connect_attrs" do
|
484
|
+
client = new_client(connect_attrs: { program_name: 'my_program_name', foo: 'fooval', bar: 'barval' })
|
485
|
+
if Mysql2::Client::CONNECT_ATTRS.zero? || client.server_info[:version].match(/10.[01].\d+-MariaDB/)
|
486
|
+
pending('Both client and server versions must be MySQL 5.6 or MariaDB 10.2 or later.')
|
487
|
+
end
|
488
|
+
results = Hash[client.query("SELECT * FROM performance_schema.session_account_connect_attrs WHERE processlist_id = connection_id()").map { |x| x.values_at('ATTR_NAME', 'ATTR_VALUE') }]
|
489
|
+
expect(results['program_name']).to eq('my_program_name')
|
490
|
+
expect(results['foo']).to eq('fooval')
|
491
|
+
expect(results['bar']).to eq('barval')
|
492
|
+
end
|
493
|
+
|
438
494
|
context "#query" do
|
439
495
|
it "should let you query again if iterating is finished when streaming" do
|
440
|
-
@client.query("SELECT 1 UNION SELECT 2", :
|
496
|
+
@client.query("SELECT 1 UNION SELECT 2", stream: true, cache_rows: false).each.to_a
|
441
497
|
|
442
|
-
expect
|
443
|
-
@client.query("SELECT 1 UNION SELECT 2", :
|
444
|
-
|
498
|
+
expect do
|
499
|
+
@client.query("SELECT 1 UNION SELECT 2", stream: true, cache_rows: false)
|
500
|
+
end.to_not raise_error
|
445
501
|
end
|
446
502
|
|
447
503
|
it "should not let you query again if iterating is not finished when streaming" do
|
448
|
-
@client.query("SELECT 1 UNION SELECT 2", :
|
504
|
+
@client.query("SELECT 1 UNION SELECT 2", stream: true, cache_rows: false).first
|
449
505
|
|
450
|
-
expect
|
451
|
-
@client.query("SELECT 1 UNION SELECT 2", :
|
452
|
-
|
506
|
+
expect do
|
507
|
+
@client.query("SELECT 1 UNION SELECT 2", stream: true, cache_rows: false)
|
508
|
+
end.to raise_exception(Mysql2::Error)
|
453
509
|
end
|
454
510
|
|
455
511
|
it "should only accept strings as the query parameter" do
|
456
|
-
expect
|
512
|
+
expect do
|
457
513
|
@client.query ["SELECT 'not right'"]
|
458
|
-
|
514
|
+
end.to raise_error(TypeError)
|
459
515
|
end
|
460
516
|
|
461
517
|
it "should not retain query options set on a query for subsequent queries, but should retain it in the result" do
|
462
|
-
result = @client.query "SELECT 1", :
|
518
|
+
result = @client.query "SELECT 1", something: :else
|
463
519
|
expect(@client.query_options[:something]).to be_nil
|
464
|
-
expect(result.instance_variable_get('@query_options')).to eql(@client.query_options.merge(:
|
465
|
-
expect(@client.instance_variable_get('@current_query_options')).to eql(@client.query_options.merge(:
|
520
|
+
expect(result.instance_variable_get('@query_options')).to eql(@client.query_options.merge(something: :else))
|
521
|
+
expect(@client.instance_variable_get('@current_query_options')).to eql(@client.query_options.merge(something: :else))
|
466
522
|
|
467
523
|
result = @client.query "SELECT 1"
|
468
524
|
expect(result.instance_variable_get('@query_options')).to eql(@client.query_options)
|
@@ -470,7 +526,7 @@ RSpec.describe Mysql2::Client do
|
|
470
526
|
end
|
471
527
|
|
472
528
|
it "should allow changing query options for subsequent queries" do
|
473
|
-
@client.query_options
|
529
|
+
@client.query_options[:something] = :else
|
474
530
|
result = @client.query "SELECT 1"
|
475
531
|
expect(@client.query_options[:something]).to eql(:else)
|
476
532
|
expect(result.instance_variable_get('@query_options')[:something]).to eql(:else)
|
@@ -485,19 +541,19 @@ RSpec.describe Mysql2::Client do
|
|
485
541
|
end
|
486
542
|
|
487
543
|
it "should be able to return results as an array" do
|
488
|
-
expect(@client.query("SELECT 1", :
|
489
|
-
@client.query("SELECT 1").each(:
|
544
|
+
expect(@client.query("SELECT 1", as: :array).first).to be_an_instance_of(Array)
|
545
|
+
@client.query("SELECT 1").each(as: :array)
|
490
546
|
end
|
491
547
|
|
492
548
|
it "should be able to return results with symbolized keys" do
|
493
|
-
expect(@client.query("SELECT 1", :
|
549
|
+
expect(@client.query("SELECT 1", symbolize_keys: true).first.keys[0]).to be_an_instance_of(Symbol)
|
494
550
|
end
|
495
551
|
|
496
552
|
it "should require an open connection" do
|
497
553
|
@client.close
|
498
|
-
expect
|
554
|
+
expect do
|
499
555
|
@client.query "SELECT 1"
|
500
|
-
|
556
|
+
end.to raise_error(Mysql2::Error)
|
501
557
|
end
|
502
558
|
|
503
559
|
it "should detect closed connection on query read error" do
|
@@ -508,37 +564,37 @@ RSpec.describe Mysql2::Client do
|
|
508
564
|
supervisor.query("KILL #{connection_id}")
|
509
565
|
end.close
|
510
566
|
end
|
511
|
-
expect
|
567
|
+
expect do
|
512
568
|
@client.query("SELECT SLEEP(1)")
|
513
|
-
|
569
|
+
end.to raise_error(Mysql2::Error, /Lost connection to MySQL server/)
|
514
570
|
|
515
571
|
if RUBY_PLATFORM !~ /mingw|mswin/
|
516
|
-
expect
|
572
|
+
expect do
|
517
573
|
@client.socket
|
518
|
-
|
574
|
+
end.to raise_error(Mysql2::Error, 'MySQL client is not connected')
|
519
575
|
end
|
520
576
|
end
|
521
577
|
|
522
578
|
if RUBY_PLATFORM !~ /mingw|mswin/
|
523
579
|
it "should not allow another query to be sent without fetching a result first" do
|
524
|
-
@client.query("SELECT 1", :
|
525
|
-
expect
|
580
|
+
@client.query("SELECT 1", async: true)
|
581
|
+
expect do
|
526
582
|
@client.query("SELECT 1")
|
527
|
-
|
583
|
+
end.to raise_error(Mysql2::Error)
|
528
584
|
end
|
529
585
|
|
530
586
|
it "should describe the thread holding the active query" do
|
531
|
-
thr = Thread.new { @client.query("SELECT 1", :
|
587
|
+
thr = Thread.new { @client.query("SELECT 1", async: true) }
|
532
588
|
|
533
589
|
thr.join
|
534
590
|
expect { @client.query('SELECT 1') }.to raise_error(Mysql2::Error, Regexp.new(Regexp.escape(thr.inspect)))
|
535
591
|
end
|
536
592
|
|
537
593
|
it "should timeout if we wait longer than :read_timeout" do
|
538
|
-
client = new_client(:
|
539
|
-
expect
|
594
|
+
client = new_client(read_timeout: 0)
|
595
|
+
expect do
|
540
596
|
client.query('SELECT SLEEP(0.1)')
|
541
|
-
|
597
|
+
end.to raise_error(Mysql2::Error::TimeoutError)
|
542
598
|
end
|
543
599
|
|
544
600
|
# XXX this test is not deterministic (because Unix signal handling is not)
|
@@ -572,22 +628,18 @@ RSpec.describe Mysql2::Client do
|
|
572
628
|
end
|
573
629
|
|
574
630
|
it "#socket should return a Fixnum (file descriptor from C)" do
|
575
|
-
expect(@client.socket).to be_an_instance_of(
|
631
|
+
expect(@client.socket).to be_an_instance_of(0.class)
|
576
632
|
expect(@client.socket).not_to eql(0)
|
577
633
|
end
|
578
634
|
|
579
635
|
it "#socket should require an open connection" do
|
580
636
|
@client.close
|
581
|
-
expect
|
637
|
+
expect do
|
582
638
|
@client.socket
|
583
|
-
|
639
|
+
end.to raise_error(Mysql2::Error)
|
584
640
|
end
|
585
641
|
|
586
642
|
it 'should be impervious to connection-corrupting timeouts in #execute' do
|
587
|
-
# the statement handle gets corrupted and will segfault the tests if interrupted,
|
588
|
-
# so we can't even use pending on this test, really have to skip it on older Rubies.
|
589
|
-
skip('`Thread.handle_interrupt` is not defined') unless Thread.respond_to?(:handle_interrupt)
|
590
|
-
|
591
643
|
# attempt to break the connection
|
592
644
|
stmt = @client.prepare('SELECT SLEEP(?)')
|
593
645
|
expect { Timeout.timeout(0.1) { stmt.execute(0.2) } }.to raise_error(Timeout::Error)
|
@@ -608,7 +660,7 @@ RSpec.describe Mysql2::Client do
|
|
608
660
|
pending('MySQL 5.5 on OSX is afflicted by an unknown bug that breaks this test. See #633 and #634.')
|
609
661
|
end
|
610
662
|
|
611
|
-
client = new_client(:
|
663
|
+
client = new_client(reconnect: true)
|
612
664
|
|
613
665
|
expect { Timeout.timeout(0.1, ArgumentError) { client.query('SELECT SLEEP(1)') } }.to raise_error(ArgumentError)
|
614
666
|
expect { client.query('SELECT 1') }.to_not raise_error
|
@@ -635,7 +687,7 @@ RSpec.describe Mysql2::Client do
|
|
635
687
|
sleep_time = 0.5
|
636
688
|
|
637
689
|
# Note that each thread opens its own database connection
|
638
|
-
threads = 5
|
690
|
+
threads = Array.new(5) do
|
639
691
|
Thread.new do
|
640
692
|
new_client do |client|
|
641
693
|
client.query("SELECT SLEEP(#{sleep_time})")
|
@@ -652,19 +704,12 @@ RSpec.describe Mysql2::Client do
|
|
652
704
|
end
|
653
705
|
|
654
706
|
it "evented async queries should be supported" do
|
655
|
-
skip("ruby 1.8 doesn't support IO.for_fd options") if RUBY_VERSION.start_with?("1.8.")
|
656
707
|
# should immediately return nil
|
657
|
-
expect(@client.query("SELECT sleep(0.1)", :
|
708
|
+
expect(@client.query("SELECT sleep(0.1)", async: true)).to eql(nil)
|
658
709
|
|
659
|
-
io_wrapper = IO.for_fd(@client.socket, :
|
710
|
+
io_wrapper = IO.for_fd(@client.socket, autoclose: false)
|
660
711
|
loops = 0
|
661
|
-
|
662
|
-
if IO.select([io_wrapper], nil, nil, 0.05)
|
663
|
-
break
|
664
|
-
else
|
665
|
-
loops += 1
|
666
|
-
end
|
667
|
-
end
|
712
|
+
loops += 1 until IO.select([io_wrapper], nil, nil, 0.05)
|
668
713
|
|
669
714
|
# make sure we waited some period of time
|
670
715
|
expect(loops >= 1).to be true
|
@@ -676,15 +721,15 @@ RSpec.describe Mysql2::Client do
|
|
676
721
|
|
677
722
|
context "Multiple results sets" do
|
678
723
|
before(:each) do
|
679
|
-
@multi_client = new_client(:
|
724
|
+
@multi_client = new_client(flags: Mysql2::Client::MULTI_STATEMENTS)
|
680
725
|
end
|
681
726
|
|
682
727
|
it "should raise an exception when one of multiple statements fails" do
|
683
728
|
result = @multi_client.query("SELECT 1 AS 'set_1'; SELECT * FROM invalid_table_name; SELECT 2 AS 'set_2';")
|
684
729
|
expect(result.first['set_1']).to be(1)
|
685
|
-
expect
|
730
|
+
expect do
|
686
731
|
@multi_client.next_result
|
687
|
-
|
732
|
+
end.to raise_error(Mysql2::Error)
|
688
733
|
expect(@multi_client.next_result).to be false
|
689
734
|
end
|
690
735
|
|
@@ -706,17 +751,17 @@ RSpec.describe Mysql2::Client do
|
|
706
751
|
|
707
752
|
it "will raise on query if there are outstanding results to read" do
|
708
753
|
@multi_client.query("SELECT 1; SELECT 2; SELECT 3")
|
709
|
-
expect
|
754
|
+
expect do
|
710
755
|
@multi_client.query("SELECT 4")
|
711
|
-
|
756
|
+
end.to raise_error(Mysql2::Error)
|
712
757
|
end
|
713
758
|
|
714
759
|
it "#abandon_results! should work" do
|
715
760
|
@multi_client.query("SELECT 1; SELECT 2; SELECT 3")
|
716
761
|
@multi_client.abandon_results!
|
717
|
-
expect
|
762
|
+
expect do
|
718
763
|
@multi_client.query("SELECT 4")
|
719
|
-
|
764
|
+
end.not_to raise_error
|
720
765
|
end
|
721
766
|
|
722
767
|
it "#more_results? should work" do
|
@@ -752,9 +797,9 @@ RSpec.describe Mysql2::Client do
|
|
752
797
|
|
753
798
|
if RUBY_PLATFORM =~ /mingw|mswin/
|
754
799
|
it "#socket should raise as it's not supported" do
|
755
|
-
expect
|
800
|
+
expect do
|
756
801
|
@client.socket
|
757
|
-
|
802
|
+
end.to raise_error(Mysql2::Error, /Raw access to the mysql file descriptor isn't supported on Windows/)
|
758
803
|
end
|
759
804
|
end
|
760
805
|
|
@@ -773,27 +818,25 @@ RSpec.describe Mysql2::Client do
|
|
773
818
|
end
|
774
819
|
|
775
820
|
it "should not overflow the thread stack" do
|
776
|
-
expect
|
821
|
+
expect do
|
777
822
|
Thread.new { Mysql2::Client.escape("'" * 256 * 1024) }.join
|
778
|
-
|
823
|
+
end.not_to raise_error
|
779
824
|
end
|
780
825
|
|
781
826
|
it "should not overflow the process stack" do
|
782
|
-
expect
|
827
|
+
expect do
|
783
828
|
Thread.new { Mysql2::Client.escape("'" * 1024 * 1024 * 4) }.join
|
784
|
-
|
829
|
+
end.not_to raise_error
|
785
830
|
end
|
786
831
|
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
expect(escaped.encoding).to eql(str.encoding)
|
832
|
+
it "should carry over the original string's encoding" do
|
833
|
+
str = "abc'def\"ghi\0jkl%mno"
|
834
|
+
escaped = Mysql2::Client.escape(str)
|
835
|
+
expect(escaped.encoding).to eql(str.encoding)
|
792
836
|
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
end
|
837
|
+
str.encode!('us-ascii')
|
838
|
+
escaped = Mysql2::Client.escape(str)
|
839
|
+
expect(escaped.encoding).to eql(str.encoding)
|
797
840
|
end
|
798
841
|
end
|
799
842
|
|
@@ -812,28 +855,26 @@ RSpec.describe Mysql2::Client do
|
|
812
855
|
end
|
813
856
|
|
814
857
|
it "should not overflow the thread stack" do
|
815
|
-
expect
|
858
|
+
expect do
|
816
859
|
Thread.new { @client.escape("'" * 256 * 1024) }.join
|
817
|
-
|
860
|
+
end.not_to raise_error
|
818
861
|
end
|
819
862
|
|
820
863
|
it "should not overflow the process stack" do
|
821
|
-
expect
|
864
|
+
expect do
|
822
865
|
Thread.new { @client.escape("'" * 1024 * 1024 * 4) }.join
|
823
|
-
|
866
|
+
end.not_to raise_error
|
824
867
|
end
|
825
868
|
|
826
869
|
it "should require an open connection" do
|
827
870
|
@client.close
|
828
|
-
expect
|
871
|
+
expect do
|
829
872
|
@client.escape ""
|
830
|
-
|
873
|
+
end.to raise_error(Mysql2::Error)
|
831
874
|
end
|
832
875
|
|
833
876
|
context 'when mysql encoding is not utf8' do
|
834
|
-
|
835
|
-
|
836
|
-
let(:client) { new_client(:encoding => "ujis") }
|
877
|
+
let(:client) { new_client(encoding: "ujis") }
|
837
878
|
|
838
879
|
it 'should return a internal encoding string if Encoding.default_internal is set' do
|
839
880
|
with_internal_encoding Encoding::UTF_8 do
|
@@ -852,14 +893,12 @@ RSpec.describe Mysql2::Client do
|
|
852
893
|
info = @client.info
|
853
894
|
expect(info).to be_an_instance_of(Hash)
|
854
895
|
expect(info).to have_key(:id)
|
855
|
-
expect(info[:id]).to be_an_instance_of(
|
896
|
+
expect(info[:id]).to be_an_instance_of(0.class)
|
856
897
|
expect(info).to have_key(:version)
|
857
898
|
expect(info[:version]).to be_an_instance_of(String)
|
858
899
|
end
|
859
900
|
|
860
901
|
context "strings returned by #info" do
|
861
|
-
before { pending('Encoding is undefined') unless defined?(Encoding) }
|
862
|
-
|
863
902
|
it "should be tagged as ascii" do
|
864
903
|
expect(@client.info[:version].encoding).to eql(Encoding::US_ASCII)
|
865
904
|
expect(@client.info[:header_version].encoding).to eql(Encoding::US_ASCII)
|
@@ -867,8 +906,6 @@ RSpec.describe Mysql2::Client do
|
|
867
906
|
end
|
868
907
|
|
869
908
|
context "strings returned by .info" do
|
870
|
-
before { pending('Encoding is undefined') unless defined?(Encoding) }
|
871
|
-
|
872
909
|
it "should be tagged as ascii" do
|
873
910
|
expect(Mysql2::Client.info[:version].encoding).to eql(Encoding::US_ASCII)
|
874
911
|
expect(Mysql2::Client.info[:header_version].encoding).to eql(Encoding::US_ASCII)
|
@@ -883,26 +920,24 @@ RSpec.describe Mysql2::Client do
|
|
883
920
|
server_info = @client.server_info
|
884
921
|
expect(server_info).to be_an_instance_of(Hash)
|
885
922
|
expect(server_info).to have_key(:id)
|
886
|
-
expect(server_info[:id]).to be_an_instance_of(
|
923
|
+
expect(server_info[:id]).to be_an_instance_of(0.class)
|
887
924
|
expect(server_info).to have_key(:version)
|
888
925
|
expect(server_info[:version]).to be_an_instance_of(String)
|
889
926
|
end
|
890
927
|
|
891
928
|
it "#server_info should require an open connection" do
|
892
929
|
@client.close
|
893
|
-
expect
|
930
|
+
expect do
|
894
931
|
@client.server_info
|
895
|
-
|
932
|
+
end.to raise_error(Mysql2::Error)
|
896
933
|
end
|
897
934
|
|
898
935
|
context "strings returned by #server_info" do
|
899
|
-
before { pending('Encoding is undefined') unless defined?(Encoding) }
|
900
|
-
|
901
936
|
it "should default to the connection's encoding if Encoding.default_internal is nil" do
|
902
937
|
with_internal_encoding nil do
|
903
938
|
expect(@client.server_info[:version].encoding).to eql(Encoding::UTF_8)
|
904
939
|
|
905
|
-
client2 = new_client(:
|
940
|
+
client2 = new_client(encoding: 'ascii')
|
906
941
|
expect(client2.server_info[:version].encoding).to eql(Encoding::ASCII)
|
907
942
|
end
|
908
943
|
end
|
@@ -918,14 +953,14 @@ RSpec.describe Mysql2::Client do
|
|
918
953
|
end
|
919
954
|
end
|
920
955
|
|
921
|
-
it "should raise a Mysql2::Error exception upon connection failure" do
|
922
|
-
expect
|
923
|
-
new_client(:
|
924
|
-
|
956
|
+
it "should raise a Mysql2::Error::ConnectionError exception upon connection failure due to invalid credentials" do
|
957
|
+
expect do
|
958
|
+
new_client(host: 'localhost', username: 'asdfasdf8d2h', password: 'asdfasdfw42')
|
959
|
+
end.to raise_error(Mysql2::Error::ConnectionError)
|
925
960
|
|
926
|
-
expect
|
961
|
+
expect do
|
927
962
|
new_client(DatabaseCredentials['root'])
|
928
|
-
|
963
|
+
end.not_to raise_error
|
929
964
|
end
|
930
965
|
|
931
966
|
context 'write operations api' do
|
@@ -974,7 +1009,7 @@ RSpec.describe Mysql2::Client do
|
|
974
1009
|
end
|
975
1010
|
|
976
1011
|
it "#thread_id should be a Fixnum" do
|
977
|
-
expect(@client.thread_id).to be_an_instance_of(
|
1012
|
+
expect(@client.thread_id).to be_an_instance_of(0.class)
|
978
1013
|
end
|
979
1014
|
|
980
1015
|
it "should respond to #ping" do
|
@@ -1010,9 +1045,9 @@ RSpec.describe Mysql2::Client do
|
|
1010
1045
|
end
|
1011
1046
|
|
1012
1047
|
it "should raise a Mysql2::Error when the database doesn't exist" do
|
1013
|
-
expect
|
1048
|
+
expect do
|
1014
1049
|
@client.select_db("nopenothere")
|
1015
|
-
|
1050
|
+
end.to raise_error(Mysql2::Error)
|
1016
1051
|
end
|
1017
1052
|
|
1018
1053
|
it "should return the database switched to" do
|
@@ -1027,13 +1062,11 @@ RSpec.describe Mysql2::Client do
|
|
1027
1062
|
end
|
1028
1063
|
|
1029
1064
|
it "should be able to connect using plaintext password" do
|
1030
|
-
client = new_client(:
|
1065
|
+
client = new_client(enable_cleartext_plugin: true)
|
1031
1066
|
client.query('SELECT 1')
|
1032
1067
|
end
|
1033
1068
|
|
1034
|
-
|
1035
|
-
|
1036
|
-
expect(@client).to respond_to(:encoding)
|
1037
|
-
end
|
1069
|
+
it "should respond to #encoding" do
|
1070
|
+
expect(@client).to respond_to(:encoding)
|
1038
1071
|
end
|
1039
1072
|
end
|