ruby-mysql 2.10.0 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -116,6 +116,13 @@ class Mysql
116
116
  OPT_ZSTD_COMPRESSION_LEVEL = 42
117
117
  OPT_LOAD_DATA_LOCAL_DIR = 43
118
118
 
119
+ # SSL Mode
120
+ SSL_MODE_DISABLED = 1
121
+ SSL_MODE_PREFERRED = 2
122
+ SSL_MODE_REQUIRED = 3
123
+ SSL_MODE_VERIFY_CA = 4
124
+ SSL_MODE_VERIFY_IDENTITY = 5
125
+
119
126
  # Server Option
120
127
  OPTION_MULTI_STATEMENTS_ON = 0
121
128
  OPTION_MULTI_STATEMENTS_OFF = 1
data/lib/mysql/error.rb CHANGED
@@ -20,17 +20,14 @@ class Mysql
20
20
  end
21
21
  end
22
22
 
23
- attr_reader :sqlstate, :error
23
+ attr_reader :sqlstate, :error, :errno
24
24
 
25
- def initialize(message, sqlstate='HY000')
25
+ def initialize(message, sqlstate='HY000', errno=nil)
26
26
  @sqlstate = sqlstate
27
27
  @error = message
28
+ @errno = errno || self.class::ERRNO
28
29
  super message
29
30
  end
30
-
31
- def errno
32
- self.class::ERRNO
33
- end
34
31
  end
35
32
 
36
33
  # server side error
@@ -3,9 +3,9 @@
3
3
  # mailto:tommy@tmtm.org
4
4
 
5
5
  require "socket"
6
- require "timeout"
7
- require "digest/sha1"
8
6
  require "stringio"
7
+ require "openssl"
8
+ require_relative 'authenticator.rb'
9
9
 
10
10
  class Mysql
11
11
  # MySQL network protocol
@@ -112,12 +112,14 @@ class Mysql
112
112
  attr_reader :server_info
113
113
  attr_reader :server_version
114
114
  attr_reader :thread_id
115
+ attr_reader :client_flags
115
116
  attr_reader :sqlstate
116
117
  attr_reader :affected_rows
117
118
  attr_reader :insert_id
118
119
  attr_reader :server_status
119
120
  attr_reader :warning_count
120
121
  attr_reader :message
122
+ attr_reader :get_server_public_key
121
123
  attr_accessor :charset
122
124
 
123
125
  # @state variable keep state for connection.
@@ -127,41 +129,38 @@ class Mysql
127
129
  # :RESULT :: After retr_fields(), retr_all_records() or stmt_retr_all_records() is needed.
128
130
 
129
131
  # make socket connection to server.
130
- # === Argument
131
- # host :: [String] if "localhost" or "" nil then use UNIXSocket. Otherwise use TCPSocket
132
- # port :: [Integer] port number using by TCPSocket
133
- # socket :: [String] socket file name using by UNIXSocket
134
- # conn_timeout :: [Integer] connect timeout (sec).
135
- # read_timeout :: [Integer] read timeout (sec).
136
- # write_timeout :: [Integer] write timeout (sec).
137
- # local_infile :: [String] local infile path
138
- # === Exception
139
- # [ClientError] :: connection timeout
140
- def initialize(host, port, socket, conn_timeout, read_timeout, write_timeout, local_infile)
132
+ # @param host [String] if "localhost" or "" or nil then use UNIX socket. Otherwise use TCP socket
133
+ # @param port [Integer] port number using by TCP socket
134
+ # @param socket [String] socket file name using by UNIX socket
135
+ # @param [Hash] opts
136
+ # @option opts :conn_timeout [Integer] connect timeout (sec).
137
+ # @option opts :read_timeout [Integer] read timeout (sec).
138
+ # @option opts :write_timeout [Integer] write timeout (sec).
139
+ # @option opts :local_infile [String] local infile path
140
+ # @option opts :get_server_public_key [Boolean]
141
+ # @raise [ClientError] connection timeout
142
+ def initialize(host, port, socket, opts)
143
+ @opts = opts
141
144
  @insert_id = 0
142
145
  @warning_count = 0
143
146
  @gc_stmt_queue = [] # stmt id list which GC destroy.
144
147
  set_state :INIT
145
- @read_timeout = read_timeout
146
- @write_timeout = write_timeout
147
- @local_infile = local_infile
148
+ @get_server_public_key = @opts[:get_server_public_key]
148
149
  begin
149
- Timeout.timeout conn_timeout do
150
- if host.nil? or host.empty? or host == "localhost"
151
- socket ||= ENV["MYSQL_UNIX_PORT"] || MYSQL_UNIX_PORT
152
- @sock = UNIXSocket.new socket
153
- else
154
- port ||= ENV["MYSQL_TCP_PORT"] || (Socket.getservbyname("mysql","tcp") rescue MYSQL_TCP_PORT)
155
- @sock = TCPSocket.new host, port
156
- end
150
+ if host.nil? or host.empty? or host == "localhost"
151
+ socket ||= ENV["MYSQL_UNIX_PORT"] || MYSQL_UNIX_PORT
152
+ @socket = Socket.unix(socket)
153
+ else
154
+ port ||= ENV["MYSQL_TCP_PORT"] || (Socket.getservbyname("mysql","tcp") rescue MYSQL_TCP_PORT)
155
+ @socket = Socket.tcp(host, port, connect_timeout: @opts[:connect_timeout])
157
156
  end
158
- rescue Timeout::Error
157
+ rescue Errno::ETIMEDOUT
159
158
  raise ClientError, "connection timeout"
160
159
  end
161
160
  end
162
161
 
163
162
  def close
164
- @sock.close
163
+ @socket.close
165
164
  end
166
165
 
167
166
  # initial negotiate and authenticate.
@@ -180,22 +179,49 @@ class Mysql
180
179
  init_packet = InitialPacket.parse read
181
180
  @server_info = init_packet.server_version
182
181
  @server_version = init_packet.server_version.split(/\D/)[0,3].inject{|a,b|a.to_i*100+b.to_i}
182
+ @server_capabilities = init_packet.server_capabilities
183
183
  @thread_id = init_packet.thread_id
184
- client_flags = CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_TRANSACTIONS | CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION
185
- client_flags |= CLIENT_LOCAL_FILES if @local_infile
186
- client_flags |= CLIENT_CONNECT_WITH_DB if db
187
- client_flags |= flag
184
+ @client_flags = CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_TRANSACTIONS | CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION | CLIENT_PLUGIN_AUTH
185
+ @client_flags |= CLIENT_LOCAL_FILES if @opts[:local_infile]
186
+ @client_flags |= CLIENT_CONNECT_WITH_DB if db
187
+ @client_flags |= flag
188
188
  @charset = charset
189
189
  unless @charset
190
190
  @charset = Charset.by_number(init_packet.server_charset)
191
191
  @charset.encoding # raise error if unsupported charset
192
192
  end
193
- netpw = encrypt_password passwd, init_packet.scramble_buff
194
- write AuthenticationPacket.serialize(client_flags, 1024**3, @charset.number, user, netpw, db)
195
- raise ProtocolError, 'The old style password is not supported' if read.to_s == "\xfe"
193
+ enable_ssl
194
+ Authenticator.new(self).authenticate(user, passwd, db, init_packet.scramble_buff, init_packet.auth_plugin)
196
195
  set_state :READY
197
196
  end
198
197
 
198
+ def enable_ssl
199
+ case @opts[:ssl_mode]
200
+ when SSL_MODE_DISABLED
201
+ return
202
+ when SSL_MODE_PREFERRED
203
+ return if @socket.local_address.unix?
204
+ return if @server_capabilities & CLIENT_SSL == 0
205
+ when SSL_MODE_REQUIRED
206
+ if @server_capabilities & CLIENT_SSL == 0
207
+ raise ClientError::SslConnectionError, "SSL is required but the server doesn't support it"
208
+ end
209
+ else
210
+ raise ClientError, "ssl_mode #{@opts[:ssl_mode]} is not supported"
211
+ end
212
+ begin
213
+ @client_flags |= CLIENT_SSL
214
+ write Protocol::TlsAuthenticationPacket.serialize(@client_flags, 1024**3, @charset.number)
215
+ @socket = OpenSSL::SSL::SSLSocket.new(@socket)
216
+ @socket.sync_close = true
217
+ @socket.connect
218
+ rescue => e
219
+ @client_flags &= ~CLIENT_SSL
220
+ return if @opts[:ssl_mode] == SSL_MODE_PREFERRED
221
+ raise e
222
+ end
223
+ end
224
+
199
225
  # Quit command
200
226
  def quit_command
201
227
  synchronize do
@@ -248,7 +274,7 @@ class Mysql
248
274
  # send local file to server
249
275
  def send_local_file(filename)
250
276
  filename = File.absolute_path(filename)
251
- if filename.start_with? @local_infile
277
+ if filename.start_with? @opts[:local_infile]
252
278
  File.open(filename){|f| write f}
253
279
  else
254
280
  raise ClientError::LoadDataLocalInfileRejected, 'LOAD DATA LOCAL INFILE file request rejected due to restrictions on access.'
@@ -442,15 +468,13 @@ class Mysql
442
468
  @gc_stmt_queue.push stmt_id
443
469
  end
444
470
 
445
- private
446
-
447
471
  def check_state(st)
448
472
  raise 'command out of sync' unless @state == st
449
473
  end
450
474
 
451
475
  def set_state(st)
452
476
  @state = st
453
- if st == :READY
477
+ if st == :READY && !@gc_stmt_queue.empty?
454
478
  gc_disabled = GC.disable
455
479
  begin
456
480
  while st = @gc_stmt_queue.shift
@@ -486,20 +510,18 @@ class Mysql
486
510
  data = ''
487
511
  len = nil
488
512
  begin
489
- Timeout.timeout @read_timeout do
490
- header = @sock.read(4)
491
- raise EOFError unless header && header.length == 4
492
- len1, len2, seq = header.unpack("CvC")
493
- len = (len2 << 8) + len1
494
- raise ProtocolError, "invalid packet: sequence number mismatch(#{seq} != #{@seq}(expected))" if @seq != seq
495
- @seq = (@seq + 1) % 256
496
- ret = @sock.read(len)
497
- raise EOFError unless ret && ret.length == len
498
- data.concat ret
499
- end
513
+ header = read_timeout(4, @opts[:read_timeout])
514
+ raise EOFError unless header && header.length == 4
515
+ len1, len2, seq = header.unpack("CvC")
516
+ len = (len2 << 8) + len1
517
+ raise ProtocolError, "invalid packet: sequence number mismatch(#{seq} != #{@seq}(expected))" if @seq != seq
518
+ @seq = (@seq + 1) % 256
519
+ ret = read_timeout(len, @opts[:read_timeout])
520
+ raise EOFError unless ret && ret.length == len
521
+ data.concat ret
500
522
  rescue EOFError
501
523
  raise ClientError::ServerGoneError, 'MySQL server has gone away'
502
- rescue Timeout::Error
524
+ rescue Errno::ETIMEDOUT
503
525
  raise ClientError, "read timeout"
504
526
  end while len == MAX_PACKET_LENGTH
505
527
 
@@ -507,52 +529,87 @@ class Mysql
507
529
 
508
530
  # Error packet
509
531
  if data[0] == ?\xff
510
- f, errno, marker, @sqlstate, message = data.unpack("Cvaa5a*")
532
+ _, errno, marker, @sqlstate, message = data.unpack("Cvaa5a*")
511
533
  unless marker == "#"
512
- f, errno, message = data.unpack("Cva*") # Version 4.0 Error
534
+ _, errno, message = data.unpack("Cva*") # Version 4.0 Error
513
535
  @sqlstate = ""
514
536
  end
515
537
  message.force_encoding(@charset.encoding)
516
538
  if Mysql::ServerError::ERROR_MAP.key? errno
517
539
  raise Mysql::ServerError::ERROR_MAP[errno].new(message, @sqlstate)
518
540
  end
519
- raise Mysql::ServerError.new(message, @sqlstate)
541
+ raise Mysql::ServerError.new(message, @sqlstate, errno)
520
542
  end
521
543
  Packet.new(data)
522
544
  end
523
545
 
546
+ def read_timeout(len, timeout)
547
+ return @socket.read(len) if timeout.nil? || timeout == 0
548
+ result = ''
549
+ e = ::Time.now + timeout
550
+ while result.size < len
551
+ now = ::Time.now
552
+ raise Errno::ETIMEDOUT if now > e
553
+ r = @socket.read_nonblock(len - result.size, exception: false)
554
+ case r
555
+ when :wait_readable
556
+ IO.select([@socket], nil, nil, e - now)
557
+ next
558
+ when :wait_writable
559
+ IO.select(nil, [@socket], nil, e - now)
560
+ next
561
+ else
562
+ result << r
563
+ end
564
+ end
565
+ return result
566
+ end
567
+
524
568
  # Write one packet data
525
569
  # === Argument
526
570
  # data :: [String / IO] packet data. If data is nil, write empty packet.
527
571
  def write(data)
528
572
  begin
529
- @sock.sync = false
573
+ @socket.sync = false
530
574
  if data.nil?
531
- Timeout.timeout @write_timeout do
532
- @sock.write [0, 0, @seq].pack("CvC")
533
- end
575
+ write_timeout([0, 0, @seq].pack("CvC"), @opts[:write_timeout])
534
576
  @seq = (@seq + 1) % 256
535
577
  else
536
578
  data = StringIO.new data if data.is_a? String
537
579
  while d = data.read(MAX_PACKET_LENGTH)
538
- Timeout.timeout @write_timeout do
539
- @sock.write [d.length%256, d.length/256, @seq].pack("CvC")
540
- @sock.write d
541
- end
580
+ write_timeout([d.length%256, d.length/256, @seq].pack("CvC")+d, @opts[:write_timeout])
542
581
  @seq = (@seq + 1) % 256
543
582
  end
544
583
  end
545
- @sock.sync = true
546
- Timeout.timeout @write_timeout do
547
- @sock.flush
548
- end
584
+ @socket.sync = true
585
+ @socket.flush
549
586
  rescue Errno::EPIPE
550
587
  raise ClientError::ServerGoneError, 'MySQL server has gone away'
551
- rescue Timeout::Error
588
+ rescue Errno::ETIMEDOUT
552
589
  raise ClientError, "write timeout"
553
590
  end
554
591
  end
555
592
 
593
+ def write_timeout(data, timeout)
594
+ return @socket.write(data) if timeout.nil? || timeout == 0
595
+ len = 0
596
+ e = ::Time.now + timeout
597
+ while len < data.size
598
+ now = ::Time.now
599
+ raise Errno::ETIMEDOUT if now > e
600
+ l = @socket.write_nonblock(data[len..-1], exception: false)
601
+ case l
602
+ when :wait_readable
603
+ IO.select([@socket], nil, nil, e - now)
604
+ when :wait_writable
605
+ IO.select(nil, [@socket], nil, e - now)
606
+ else
607
+ len += l
608
+ end
609
+ end
610
+ return len
611
+ end
612
+
556
613
  # Read EOF packet
557
614
  # === Exception
558
615
  # [ProtocolError] packet is not EOF
@@ -573,19 +630,6 @@ class Mysql
573
630
  end
574
631
  end
575
632
 
576
- # Encrypt password
577
- # === Argument
578
- # plain :: [String] plain password.
579
- # scramble :: [String] scramble code from initial packet.
580
- # === Return
581
- # [String] encrypted password
582
- def encrypt_password(plain, scramble)
583
- return "" if plain.nil? or plain.empty?
584
- hash_stage1 = Digest::SHA1.digest plain
585
- hash_stage2 = Digest::SHA1.digest hash_stage1
586
- return hash_stage1.unpack("C*").zip(Digest::SHA1.digest(scramble+hash_stage2).unpack("C*")).map{|a,b| a^b}.pack("C*")
587
- end
588
-
589
633
  # Initial packet
590
634
  class InitialPacket
591
635
  def self.parse(pkt)
@@ -597,18 +641,26 @@ class Mysql
597
641
  server_capabilities = pkt.ushort
598
642
  server_charset = pkt.utiny
599
643
  server_status = pkt.ushort
600
- _f1 = pkt.read(13)
644
+ server_capabilities2 = pkt.ushort
645
+ scramble_length = pkt.utiny
646
+ _f1 = pkt.read(10)
601
647
  rest_scramble_buff = pkt.string
648
+ auth_plugin = pkt.string
649
+
650
+ server_capabilities |= server_capabilities2 << 16
651
+ scramble_buff.concat rest_scramble_buff
652
+
602
653
  raise ProtocolError, "unsupported version: #{protocol_version}" unless protocol_version == VERSION
603
654
  raise ProtocolError, "invalid packet: f0=#{f0}" unless f0 == 0
604
- scramble_buff.concat rest_scramble_buff
605
- self.new protocol_version, server_version, thread_id, server_capabilities, server_charset, server_status, scramble_buff
655
+ raise ProtocolError, "invalid packet: scramble_length(#{scramble_length}) != length of scramble(#{scramble_buff.size + 1})" unless scramble_length == scramble_buff.size + 1
656
+
657
+ self.new protocol_version, server_version, thread_id, server_capabilities, server_charset, server_status, scramble_buff, auth_plugin
606
658
  end
607
659
 
608
- attr_reader :protocol_version, :server_version, :thread_id, :server_capabilities, :server_charset, :server_status, :scramble_buff
660
+ attr_reader :protocol_version, :server_version, :thread_id, :server_capabilities, :server_charset, :server_status, :scramble_buff, :auth_plugin
609
661
 
610
662
  def initialize(*args)
611
- @protocol_version, @server_version, @thread_id, @server_capabilities, @server_charset, @server_status, @scramble_buff = args
663
+ @protocol_version, @server_version, @thread_id, @server_capabilities, @server_charset, @server_status, @scramble_buff, @auth_plugin = args
612
664
  end
613
665
  end
614
666
 
@@ -688,16 +740,35 @@ class Mysql
688
740
 
689
741
  # Authentication packet
690
742
  class AuthenticationPacket
691
- def self.serialize(client_flags, max_packet_size, charset_number, username, scrambled_password, databasename)
692
- [
743
+ def self.serialize(client_flags, max_packet_size, charset_number, username, scrambled_password, databasename, auth_plugin)
744
+ data = [
693
745
  client_flags,
694
746
  max_packet_size,
695
- Packet.lcb(charset_number),
747
+ charset_number,
696
748
  "", # always 0x00 * 23
697
749
  username,
698
750
  Packet.lcs(scrambled_password),
699
- databasename
700
- ].pack("VVa*a23Z*A*Z*")
751
+ ]
752
+ pack = "VVCa23Z*A*"
753
+ if databasename
754
+ data.push databasename
755
+ pack.concat "Z*"
756
+ end
757
+ data.push auth_plugin
758
+ pack.concat "Z*"
759
+ data.pack(pack)
760
+ end
761
+ end
762
+
763
+ # TLS Authentication packet
764
+ class TlsAuthenticationPacket
765
+ def self.serialize(client_flags, max_packet_size, charset_number)
766
+ [
767
+ client_flags,
768
+ max_packet_size,
769
+ charset_number,
770
+ "", # always 0x00 * 23
771
+ ].pack("VVCa23")
701
772
  end
702
773
  end
703
774
 
@@ -725,6 +796,21 @@ class Mysql
725
796
  end
726
797
 
727
798
  end
799
+
800
+ class AuthenticationResultPacket
801
+ def self.parse(pkt)
802
+ result = pkt.utiny
803
+ auth_plugin = pkt.string
804
+ scramble = pkt.string
805
+ self.new(result, auth_plugin, scramble)
806
+ end
807
+
808
+ attr_reader :result, :auth_plugin, :scramble
809
+
810
+ def initialize(*args)
811
+ @result, @auth_plugin, @scramble = args
812
+ end
813
+ end
728
814
  end
729
815
 
730
816
  class RawRecord
data/lib/mysql.rb CHANGED
@@ -16,12 +16,8 @@ class Mysql
16
16
  require "mysql/charset"
17
17
  require "mysql/protocol"
18
18
  require "mysql/packet.rb"
19
- begin
20
- require "mysql/ext.so"
21
- rescue LoadError
22
- end
23
19
 
24
- VERSION = 21000 # Version number of this library
20
+ VERSION = 21100 # Version number of this library
25
21
  MYSQL_UNIX_PORT = "/tmp/mysql.sock" # UNIX domain socket filename
26
22
  MYSQL_TCP_PORT = 3306 # TCP socket port number
27
23
 
@@ -86,16 +82,20 @@ class Mysql
86
82
  @fields = nil
87
83
  @protocol = nil
88
84
  @charset = nil
89
- @connect_timeout = nil
90
- @read_timeout = nil
91
- @write_timeout = nil
92
85
  @init_command = nil
93
86
  @sqlstate = "00000"
94
87
  @query_with_result = true
95
88
  @host_info = nil
96
89
  @last_error = nil
97
90
  @result_exist = false
98
- @local_infile = nil
91
+ @opts = {
92
+ connect_timeout: nil,
93
+ read_timeout: nil,
94
+ write_timeout: nil,
95
+ local_infile: nil,
96
+ ssl_mode: SSL_MODE_PREFERRED,
97
+ get_server_public_key: false,
98
+ }
99
99
  end
100
100
 
101
101
  # Connect to mysqld.
@@ -112,7 +112,7 @@ class Mysql
112
112
  warn 'unsupported flag: CLIENT_COMPRESS' if $VERBOSE
113
113
  flag &= ~CLIENT_COMPRESS
114
114
  end
115
- @protocol = Protocol.new host, port, socket, @connect_timeout, @read_timeout, @write_timeout, @local_infile
115
+ @protocol = Protocol.new(host, port, socket, @opts)
116
116
  @protocol.authenticate user, passwd, db, flag, @charset
117
117
  @charset ||= @protocol.charset
118
118
  @host_info = (host.nil? || host == "localhost") ? 'Localhost via UNIX socket' : "#{host} via TCP/IP"
@@ -144,38 +144,64 @@ class Mysql
144
144
  # Set option for connection.
145
145
  #
146
146
  # Available options:
147
- # Mysql::INIT_COMMAND, Mysql::OPT_CONNECT_TIMEOUT, Mysql::OPT_READ_TIMEOUT,
148
- # Mysql::OPT_WRITE_TIMEOUT, Mysql::SET_CHARSET_NAME
147
+ # Mysql::INIT_COMMAND, Mysql::OPT_CONNECT_TIMEOUT, Mysql::OPT_GET_SERVER_PUBLIC_KEY,
148
+ # Mysql::OPT_LOAD_DATA_LOCAL_DIR, Mysql::OPT_LOCAL_INFILE, Mysql::OPT_READ_TIMEOUT,
149
+ # Mysql::OPT_SSL_MODE, Mysql::OPT_WRITE_TIMEOUT, Mysql::SET_CHARSET_NAME
149
150
  # @param [Integer] opt option
150
151
  # @param [Integer] value option value that is depend on opt
151
152
  # @return [Mysql] self
152
153
  def options(opt, value=nil)
153
154
  case opt
155
+ # when Mysql::DEFAULT_AUTH
156
+ # when Mysql::ENABLE_CLEARTEXT_PLUGIN
154
157
  when Mysql::INIT_COMMAND
155
158
  @init_command = value.to_s
159
+ # when Mysql::OPT_BIND
160
+ # when Mysql::OPT_CAN_HANDLE_EXPIRED_PASSWORDS
156
161
  # when Mysql::OPT_COMPRESS
162
+ # when Mysql::OPT_COMPRESSION_ALGORITHMS
163
+ # when Mysql::OPT_CONNECT_ATTR_ADD
164
+ # when Mysql::OPT_CONNECT_ATTR_DELETE
165
+ # when Mysql::OPT_CONNECT_ATTR_RESET
157
166
  when Mysql::OPT_CONNECT_TIMEOUT
158
- @connect_timeout = value
159
- # when Mysql::GUESS_CONNECTION
160
- when Mysql::OPT_LOCAL_INFILE
161
- @local_infile = value ? '' : nil
167
+ @opts[:connect_timeout] = value
168
+ when Mysql::OPT_GET_SERVER_PUBLIC_KEY
169
+ @opts[:get_server_public_key] = value
162
170
  when Mysql::OPT_LOAD_DATA_LOCAL_DIR
163
- @local_infile = value
171
+ @opts[:local_infile] = value
172
+ when Mysql::OPT_LOCAL_INFILE
173
+ @opts[:local_infile] = value ? '' : nil
174
+ # when Mysql::OPT_MAX_ALLOWED_PACKET
164
175
  # when Mysql::OPT_NAMED_PIPE
176
+ # when Mysql::OPT_NET_BUFFER_LENGTH
177
+ # when Mysql::OPT_OPTIONAL_RESULTSET_METADATA
165
178
  # when Mysql::OPT_PROTOCOL
166
179
  when Mysql::OPT_READ_TIMEOUT
167
- @read_timeout = value.to_i
180
+ @opts[:read_timeout] = value
168
181
  # when Mysql::OPT_RECONNECT
182
+ # when Mysql::OPT_RETRY_COUNT
169
183
  # when Mysql::SET_CLIENT_IP
170
- # when Mysql::OPT_SSL_VERIFY_SERVER_CERT
171
- # when Mysql::OPT_USE_EMBEDDED_CONNECTION
172
- # when Mysql::OPT_USE_REMOTE_CONNECTION
184
+ # when Mysql::OPT_SSL_CA
185
+ # when Mysql::OPT_SSL_CAPATH
186
+ # when Mysql::OPT_SSL_CERT
187
+ # when Mysql::OPT_SSL_CIPHER
188
+ # when Mysql::OPT_SSL_CRL
189
+ # when Mysql::OPT_SSL_CRLPATH
190
+ # when Mysql::OPT_SSL_FIPS_MODE
191
+ # when Mysql::OPT_SSL_KEY
192
+ when Mysql::OPT_SSL_MODE
193
+ @opts[:ssl_mode] = value
194
+ # when Mysql::OPT_TLS_CIPHERSUITES
195
+ # when Mysql::OPT_TLS_VERSION
196
+ # when Mysql::OPT_USE_RESULT
173
197
  when Mysql::OPT_WRITE_TIMEOUT
174
- @write_timeout = value.to_i
198
+ @opts[:write_timeout] = value
199
+ # when Mysql::OPT_ZSTD_COMPRESSION_LEVEL
200
+ # when Mysql::PLUGIN_DIR
175
201
  # when Mysql::READ_DEFAULT_FILE
176
202
  # when Mysql::READ_DEFAULT_GROUP
177
203
  # when Mysql::REPORT_DATA_TRUNCATION
178
- # when Mysql::SECURE_AUTH
204
+ # when Mysql::SERVER_PUBLIC_KEY
179
205
  # when Mysql::SET_CHARSET_DIR
180
206
  when Mysql::SET_CHARSET_NAME
181
207
  @charset = Charset.by_name value.to_s
@@ -188,14 +214,9 @@ class Mysql
188
214
 
189
215
  # Escape special character in MySQL.
190
216
  #
191
- # In Ruby 1.8, this is not safe for multibyte charset such as 'SJIS'.
192
- # You should use place-holder in prepared-statement.
193
217
  # @param [String] str
194
218
  # return [String]
195
219
  def escape_string(str)
196
- if not defined? Encoding and @charset.unsafe
197
- raise ClientError, 'Mysql#escape_string is called for unsafe multibyte charset'
198
- end
199
220
  self.class.escape_string str
200
221
  end
201
222
  alias quote escape_string
@@ -441,7 +462,6 @@ class Mysql
441
462
  store_result
442
463
  end
443
464
 
444
- # @note for Ruby 1.8: This is not multi-byte safe. Don't use for multi-byte charset such as cp932.
445
465
  # @param [String] table database name that may contain wild card.
446
466
  # @return [Array<String>] list of table name.
447
467
  def list_tables(table=nil)
@@ -902,7 +922,7 @@ class Mysql
902
922
  row.zip(@bind_result).map do |col, type|
903
923
  if col.nil?
904
924
  nil
905
- elsif [Numeric, Integer, Fixnum].include? type
925
+ elsif [Numeric, Integer].include? type
906
926
  col.to_i
907
927
  elsif type == String
908
928
  col.to_s
@@ -955,7 +975,7 @@ class Mysql
955
975
  raise ClientError, "bind_result: result value count(#{@fields.length}) != number of argument(#{args.length})"
956
976
  end
957
977
  args.each do |a|
958
- raise TypeError unless [Numeric, Fixnum, Integer, Float, String, Mysql::Time, nil].include? a
978
+ raise TypeError unless [Numeric, Integer, Float, String, Mysql::Time, nil].include? a
959
979
  end
960
980
  @bind_result = args
961
981
  self