ruby-mysql 2.10.0 → 2.11.0

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.
@@ -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