ruby-mysql 2.11.1 → 3.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -0
- data/README.md +28 -0
- data/lib/mysql/protocol.rb +81 -147
- data/lib/mysql.rb +182 -359
- data/test/test_mysql.rb +217 -550
- metadata +10 -7
- data/README.rdoc +0 -69
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f95fb29b93c207b23bbc1378ce78b10ab297269f0cf24409116a69502cdf9ae8
|
4
|
+
data.tar.gz: 7979ccfd21194e81a4c98f90920b7dc3cdb1165201bdf7bc0d640d16fbe8ebea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '068b6f6008f4b77dc6d34b660c8f06b73db2c06e63fc98d69d5455ceb6ab61c3924d158de4398d6b897cc2fa44d460a879b60355dbb16ac90f0af666f750467d'
|
7
|
+
data.tar.gz: 769105fbd5f16a4b8ab9c55c4a1243c962db3a238f05baa16d970cb2cbaadba0f0487c2daf194b53ce0bfa48639aac37cb79527da02518607a4a0a861cdd6caf
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
## [3.0.0] - 2021-11-16
|
2
|
+
|
3
|
+
- `Mysql.new` no longer connect. use `Mysql.connect` or `Mysql#connect`.
|
4
|
+
|
5
|
+
- `Mysql.init` is removed. use `Mysql.new` instead.
|
6
|
+
|
7
|
+
- `Mysql.new`, `Mysql.conncet` and `Mysql#connect` takes URI object or URI string or Hash object.
|
8
|
+
example:
|
9
|
+
Mysql.connect('mysql://user:password@hostname:port/dbname?charset=ascii')
|
10
|
+
Mysql.connect('mysql://user:password@%2Ftmp%2Fmysql.sock/dbname?charset=ascii') # for UNIX socket
|
11
|
+
Mysql.connect('hostname', 'user', 'password', 'dbname')
|
12
|
+
Mysql.connect(host: 'hostname', username: 'user', password: 'password', database: 'dbname')
|
13
|
+
|
14
|
+
- `Mysql.options` is removed. use `Mysql#param = value` instead.
|
15
|
+
For example:
|
16
|
+
m = Mysql.init
|
17
|
+
m.options(Mysql::OPT_LOCAL_INFILE, true)
|
18
|
+
m.connect(host, user, passwd)
|
19
|
+
change to
|
20
|
+
m = Mysql.new
|
21
|
+
m.local_infile = true
|
22
|
+
m.connect(host, user, passwd)
|
23
|
+
or
|
24
|
+
m = Mysql.connect(host, user, passwd, local_infile: true)
|
25
|
+
|
26
|
+
- `Mysql::Time` is removed.
|
27
|
+
Instead, `Time` object is returned for the DATE, DATETIME, TIMESTAMP data,
|
28
|
+
and `Integer` object is returned for the TIME data.
|
29
|
+
If DATE, DATETIME, TIMESTAMP are invalid values for Time, nil is returned.
|
30
|
+
|
31
|
+
- meaningless methods are removed:
|
32
|
+
* `bind_result`
|
33
|
+
* `client_info`
|
34
|
+
* `client_version`
|
35
|
+
* `get_proto_info`
|
36
|
+
* `get_server_info`
|
37
|
+
* `get_server_version`
|
38
|
+
* `proto_info`
|
39
|
+
* `query_with_result`
|
40
|
+
|
41
|
+
- alias method are removed:
|
42
|
+
* `get_host_info`: use `host_info`
|
43
|
+
* `real_connect`: use `connect`
|
44
|
+
* `real_query`: use `query`
|
45
|
+
|
46
|
+
- methods corresponding to deprecated APIs in MySQL are removed:
|
47
|
+
* `list_dbs`: use `SHOW DATABASES`
|
48
|
+
* `list_fields`: use `SHOW COLUMNS`
|
49
|
+
* `list_processes`: use `SHOW PROCESSLIST`
|
50
|
+
* `list_tables`: use `SHOW TABLES`
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# ruby-mysql
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
MySQL connector for Ruby.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
```
|
10
|
+
gem install ruby-mysql
|
11
|
+
```
|
12
|
+
|
13
|
+
## Synopsis
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
my = Mysql.connect('mysql://username:password@hostname:port/dbname?charset=utf8mb4')
|
17
|
+
my.query("select col1, col2 from tblname").each do |col1, col2|
|
18
|
+
p col1, col2
|
19
|
+
end
|
20
|
+
stmt = my.prepare('insert into tblname (col1,col2) values (?,?)')
|
21
|
+
stmt.execute 123, 'abc'
|
22
|
+
```
|
23
|
+
|
24
|
+
## Copyright
|
25
|
+
|
26
|
+
* Author: TOMITA Masahiro <tommy@tmtm.org>
|
27
|
+
* Copyright: Copyright 2008 TOMITA Masahiro
|
28
|
+
* License: MIT
|
data/lib/mysql/protocol.rb
CHANGED
@@ -15,12 +15,10 @@ class Mysql
|
|
15
15
|
MAX_PACKET_LENGTH = 2**24-1
|
16
16
|
|
17
17
|
# Convert netdata to Ruby value
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# === Return
|
23
|
-
# Object :: converted value.
|
18
|
+
# @param data [Packet] packet data
|
19
|
+
# @param type [Integer] field type
|
20
|
+
# @param unsigned [true or false] true if value is unsigned
|
21
|
+
# @return [Object] converted value.
|
24
22
|
def self.net2value(pkt, type, unsigned)
|
25
23
|
case type
|
26
24
|
when Field::TYPE_STRING, Field::TYPE_VAR_STRING, Field::TYPE_NEWDECIMAL, Field::TYPE_BLOB, Field::TYPE_JSON
|
@@ -45,17 +43,18 @@ class Mysql
|
|
45
43
|
when Field::TYPE_DATE
|
46
44
|
len = pkt.utiny
|
47
45
|
y, m, d = pkt.read(len).unpack("vCC")
|
48
|
-
t =
|
46
|
+
t = Time.new(y, m, d) rescue nil
|
49
47
|
return t
|
50
48
|
when Field::TYPE_DATETIME, Field::TYPE_TIMESTAMP
|
51
49
|
len = pkt.utiny
|
52
50
|
y, m, d, h, mi, s, sp = pkt.read(len).unpack("vCCCCCV")
|
53
|
-
return
|
51
|
+
return Time.new(y, m, d, h, mi, Rational((s.to_i*1000000+sp.to_i)/1000000)) rescue nil
|
54
52
|
when Field::TYPE_TIME
|
55
53
|
len = pkt.utiny
|
56
54
|
sign, d, h, mi, s, sp = pkt.read(len).unpack("CVCCCV")
|
57
|
-
|
58
|
-
|
55
|
+
r = d.to_i*86400 + h.to_i*3600 + mi.to_i*60 + s.to_i + sp.to_f/1000000
|
56
|
+
r *= -1 if sign != 0
|
57
|
+
return r
|
59
58
|
when Field::TYPE_YEAR
|
60
59
|
return pkt.ushort
|
61
60
|
when Field::TYPE_BIT
|
@@ -66,13 +65,10 @@ class Mysql
|
|
66
65
|
end
|
67
66
|
|
68
67
|
# convert Ruby value to netdata
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
# String :: netdata
|
74
|
-
# === Exception
|
75
|
-
# ProtocolError :: value too large / value is not supported
|
68
|
+
# @param v [Object] Ruby value.
|
69
|
+
# @return [Integer] type of column. Field::TYPE_*
|
70
|
+
# @return [String] netdata
|
71
|
+
# @raise [ProtocolError] value too large / value is not supported
|
76
72
|
def self.value2net(v)
|
77
73
|
case v
|
78
74
|
when nil
|
@@ -97,12 +93,9 @@ class Mysql
|
|
97
93
|
when String
|
98
94
|
type = Field::TYPE_STRING
|
99
95
|
val = Packet.lcs(v)
|
100
|
-
when
|
96
|
+
when Time
|
101
97
|
type = Field::TYPE_DATETIME
|
102
98
|
val = [11, v.year, v.month, v.day, v.hour, v.min, v.sec, v.usec].pack("CvCCCCCV")
|
103
|
-
when Mysql::Time
|
104
|
-
type = Field::TYPE_DATETIME
|
105
|
-
val = [11, v.year, v.month, v.day, v.hour, v.min, v.sec, v.second_part].pack("CvCCCCCV")
|
106
99
|
else
|
107
100
|
raise ProtocolError, "class #{v.class} is not supported"
|
108
101
|
end
|
@@ -129,30 +122,38 @@ class Mysql
|
|
129
122
|
# :RESULT :: After retr_fields(), retr_all_records() or stmt_retr_all_records() is needed.
|
130
123
|
|
131
124
|
# make socket connection to server.
|
132
|
-
# @param
|
133
|
-
# @
|
134
|
-
# @
|
135
|
-
# @
|
136
|
-
# @option
|
137
|
-
# @option
|
138
|
-
# @option
|
139
|
-
# @option
|
140
|
-
# @option
|
125
|
+
# @param opts [Hash]
|
126
|
+
# @option :host [String] hostname mysqld running
|
127
|
+
# @option :username [String] username to connect to mysqld
|
128
|
+
# @option :password [String] password to connect to mysqld
|
129
|
+
# @option :database [String] initial database name
|
130
|
+
# @option :port [String] port number (used if host is not 'localhost' or nil)
|
131
|
+
# @option :socket [String] socket filename (used if host is 'localhost' or nil)
|
132
|
+
# @option :flags [Integer] connection flag. Mysql::CLIENT_* ORed
|
133
|
+
# @option :charset [Mysql::Charset] character set
|
134
|
+
# @option :connect_timeout [Numeric, nil]
|
135
|
+
# @option :read_timeout [Numeric, nil]
|
136
|
+
# @option :write_timeout [Numeric, nil]
|
137
|
+
# @option :local_infile [Boolean]
|
138
|
+
# @option :load_data_local_dir [String]
|
139
|
+
# @option :ssl_mode [Integer]
|
140
|
+
# @option :get_server_public_key [Boolean]
|
141
141
|
# @raise [ClientError] connection timeout
|
142
|
-
def initialize(
|
142
|
+
def initialize(opts)
|
143
143
|
@opts = opts
|
144
|
+
@charset = Mysql::Charset.by_name("utf8mb4")
|
144
145
|
@insert_id = 0
|
145
146
|
@warning_count = 0
|
146
147
|
@gc_stmt_queue = [] # stmt id list which GC destroy.
|
147
148
|
set_state :INIT
|
148
149
|
@get_server_public_key = @opts[:get_server_public_key]
|
149
150
|
begin
|
150
|
-
if host.nil? or host.empty? or host == "localhost"
|
151
|
-
socket
|
151
|
+
if @opts[:host].nil? or @opts[:host].empty? or @opts[:host] == "localhost"
|
152
|
+
socket = @opts[:socket] || ENV["MYSQL_UNIX_PORT"] || MYSQL_UNIX_PORT
|
152
153
|
@socket = Socket.unix(socket)
|
153
154
|
else
|
154
|
-
port
|
155
|
-
@socket = Socket.tcp(host, port, connect_timeout: @opts[:connect_timeout])
|
155
|
+
port = @opts[:port] || ENV["MYSQL_TCP_PORT"] || (Socket.getservbyname("mysql","tcp") rescue MYSQL_TCP_PORT)
|
156
|
+
@socket = Socket.tcp(@opts[:host], port, connect_timeout: @opts[:connect_timeout])
|
156
157
|
end
|
157
158
|
rescue Errno::ETIMEDOUT
|
158
159
|
raise ClientError, "connection timeout"
|
@@ -164,17 +165,10 @@ class Mysql
|
|
164
165
|
end
|
165
166
|
|
166
167
|
# initial negotiate and authenticate.
|
167
|
-
#
|
168
|
-
#
|
169
|
-
|
170
|
-
# db :: [String / nil] default database name. nil: no default.
|
171
|
-
# flag :: [Integer] client flag
|
172
|
-
# charset :: [Mysql::Charset / nil] charset for connection. nil: use server's charset
|
173
|
-
# === Exception
|
174
|
-
# ProtocolError :: The old style password is not supported
|
175
|
-
def authenticate(user, passwd, db, flag, charset)
|
168
|
+
# @param charset [Mysql::Charset, nil] charset for connection. nil: use server's charset
|
169
|
+
# @raise [ProtocolError] The old style password is not supported
|
170
|
+
def authenticate
|
176
171
|
check_state :INIT
|
177
|
-
@authinfo = [user, passwd, db, flag, charset]
|
178
172
|
reset
|
179
173
|
init_packet = InitialPacket.parse read
|
180
174
|
@server_info = init_packet.server_version
|
@@ -182,27 +176,28 @@ class Mysql
|
|
182
176
|
@server_capabilities = init_packet.server_capabilities
|
183
177
|
@thread_id = init_packet.thread_id
|
184
178
|
@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
|
187
|
-
@client_flags |=
|
188
|
-
@charset
|
189
|
-
|
179
|
+
@client_flags |= CLIENT_LOCAL_FILES if @opts[:local_infile] || @opts[:load_data_local_dir]
|
180
|
+
@client_flags |= CLIENT_CONNECT_WITH_DB if @opts[:database]
|
181
|
+
@client_flags |= @opts[:flags]
|
182
|
+
if @opts[:charset]
|
183
|
+
@charset = @opts[:charset].is_a?(Charset) ? @opts[:charset] : Charset.by_name(@opts[:charset])
|
184
|
+
else
|
190
185
|
@charset = Charset.by_number(init_packet.server_charset)
|
191
186
|
@charset.encoding # raise error if unsupported charset
|
192
187
|
end
|
193
188
|
enable_ssl
|
194
|
-
Authenticator.new(self).authenticate(
|
189
|
+
Authenticator.new(self).authenticate(@opts[:username], @opts[:password].to_s, @opts[:database], init_packet.scramble_buff, init_packet.auth_plugin)
|
195
190
|
set_state :READY
|
196
191
|
end
|
197
192
|
|
198
193
|
def enable_ssl
|
199
194
|
case @opts[:ssl_mode]
|
200
|
-
when SSL_MODE_DISABLED
|
195
|
+
when SSL_MODE_DISABLED, '1', 'disabled'
|
201
196
|
return
|
202
|
-
when SSL_MODE_PREFERRED
|
197
|
+
when SSL_MODE_PREFERRED, '2', 'preferred'
|
203
198
|
return if @socket.local_address.unix?
|
204
199
|
return if @server_capabilities & CLIENT_SSL == 0
|
205
|
-
when SSL_MODE_REQUIRED
|
200
|
+
when SSL_MODE_REQUIRED, '3', 'required'
|
206
201
|
if @server_capabilities & CLIENT_SSL == 0
|
207
202
|
raise ClientError::SslConnectionError, "SSL is required but the server doesn't support it"
|
208
203
|
end
|
@@ -232,10 +227,8 @@ class Mysql
|
|
232
227
|
end
|
233
228
|
|
234
229
|
# Query command
|
235
|
-
#
|
236
|
-
#
|
237
|
-
# === Return
|
238
|
-
# [Integer / nil] number of fields of results. nil if no results.
|
230
|
+
# @param query [String] query string
|
231
|
+
# @return [Integer, nil] number of fields of results. nil if no results.
|
239
232
|
def query_command(query)
|
240
233
|
check_state :READY
|
241
234
|
begin
|
@@ -249,8 +242,7 @@ class Mysql
|
|
249
242
|
end
|
250
243
|
|
251
244
|
# get result of query.
|
252
|
-
#
|
253
|
-
# [integer / nil] number of fields of results. nil if no results.
|
245
|
+
# @return [integer, nil] number of fields of results. nil if no results.
|
254
246
|
def get_result
|
255
247
|
begin
|
256
248
|
res_packet = ResultPacket.parse read
|
@@ -274,7 +266,7 @@ class Mysql
|
|
274
266
|
# send local file to server
|
275
267
|
def send_local_file(filename)
|
276
268
|
filename = File.absolute_path(filename)
|
277
|
-
if filename.start_with?
|
269
|
+
if @opts[:local_infile] || @opts[:load_data_local_dir] && filename.start_with?(@opts[:load_data_local_dir])
|
278
270
|
File.open(filename){|f| write f}
|
279
271
|
else
|
280
272
|
raise ClientError::LoadDataLocalInfileRejected, 'LOAD DATA LOCAL INFILE file request rejected due to restrictions on access.'
|
@@ -285,10 +277,8 @@ class Mysql
|
|
285
277
|
end
|
286
278
|
|
287
279
|
# Retrieve n fields
|
288
|
-
#
|
289
|
-
#
|
290
|
-
# === Return
|
291
|
-
# [Array of Mysql::Field] field list
|
280
|
+
# @param n [Integer] number of fields
|
281
|
+
# @return [Array<Mysql::Field>] field list
|
292
282
|
def retr_fields(n)
|
293
283
|
check_state :FIELD
|
294
284
|
begin
|
@@ -303,10 +293,8 @@ class Mysql
|
|
303
293
|
end
|
304
294
|
|
305
295
|
# Retrieve all records for simple query
|
306
|
-
#
|
307
|
-
#
|
308
|
-
# === Return
|
309
|
-
# [Array of Array of String] all records
|
296
|
+
# @param fields [Array<Mysql::Field>] number of fields
|
297
|
+
# @return [Array<Array<String>>] all records
|
310
298
|
def retr_all_records(fields)
|
311
299
|
check_state :RESULT
|
312
300
|
enc = charset.encoding
|
@@ -323,43 +311,6 @@ class Mysql
|
|
323
311
|
end
|
324
312
|
end
|
325
313
|
|
326
|
-
# Field list command
|
327
|
-
# === Argument
|
328
|
-
# table :: [String] table name.
|
329
|
-
# field :: [String / nil] field name that may contain wild card.
|
330
|
-
# === Return
|
331
|
-
# [Array of Field] field list
|
332
|
-
def field_list_command(table, field)
|
333
|
-
synchronize do
|
334
|
-
reset
|
335
|
-
write [COM_FIELD_LIST, table, 0, field].pack("Ca*Ca*")
|
336
|
-
fields = []
|
337
|
-
until (data = read).eof?
|
338
|
-
fields.push Field.new(FieldPacket.parse(data))
|
339
|
-
end
|
340
|
-
return fields
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
# Process info command
|
345
|
-
# === Return
|
346
|
-
# [Array of Field] field list
|
347
|
-
def process_info_command
|
348
|
-
check_state :READY
|
349
|
-
begin
|
350
|
-
reset
|
351
|
-
write [COM_PROCESS_INFO].pack("C")
|
352
|
-
field_count = read.lcb
|
353
|
-
fields = field_count.times.map{Field.new FieldPacket.parse(read)}
|
354
|
-
read_eof_packet
|
355
|
-
set_state :RESULT
|
356
|
-
return fields
|
357
|
-
rescue
|
358
|
-
set_state :READY
|
359
|
-
raise
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
314
|
# Ping command
|
364
315
|
def ping_command
|
365
316
|
simple_command [COM_PING].pack("C")
|
@@ -391,12 +342,8 @@ class Mysql
|
|
391
342
|
end
|
392
343
|
|
393
344
|
# Stmt prepare command
|
394
|
-
#
|
395
|
-
#
|
396
|
-
# === Return
|
397
|
-
# [Integer] statement id
|
398
|
-
# [Integer] number of parameters
|
399
|
-
# [Array of Field] field list
|
345
|
+
# @param stmt [String] prepared statement
|
346
|
+
# @return [Array<Integer, Integer, Array<Field>>] statement id, number of parameters, field list
|
400
347
|
def stmt_prepare_command(stmt)
|
401
348
|
synchronize do
|
402
349
|
reset
|
@@ -417,11 +364,9 @@ class Mysql
|
|
417
364
|
end
|
418
365
|
|
419
366
|
# Stmt execute command
|
420
|
-
#
|
421
|
-
#
|
422
|
-
#
|
423
|
-
# === Return
|
424
|
-
# [Integer] number of fields
|
367
|
+
# @param stmt_id [Integer] statement id
|
368
|
+
# @param values [Array] parameters
|
369
|
+
# @return [Integer] number of fields
|
425
370
|
def stmt_execute_command(stmt_id, values)
|
426
371
|
check_state :READY
|
427
372
|
begin
|
@@ -435,11 +380,9 @@ class Mysql
|
|
435
380
|
end
|
436
381
|
|
437
382
|
# Retrieve all records for prepared statement
|
438
|
-
#
|
439
|
-
#
|
440
|
-
#
|
441
|
-
# === Return
|
442
|
-
# [Array of Array of Object] all records
|
383
|
+
# @param fields [Array of Mysql::Fields] field list
|
384
|
+
# @param charset [Mysql::Charset]
|
385
|
+
# @return [Array<Array<Object>>] all records
|
443
386
|
def stmt_retr_all_records(fields, charset)
|
444
387
|
check_state :RESULT
|
445
388
|
enc = charset.encoding
|
@@ -455,8 +398,7 @@ class Mysql
|
|
455
398
|
end
|
456
399
|
|
457
400
|
# Stmt close command
|
458
|
-
#
|
459
|
-
# stmt_id :: [Integer] statement id
|
401
|
+
# @param stmt_id [Integer] statement id
|
460
402
|
def stmt_close_command(stmt_id)
|
461
403
|
synchronize do
|
462
404
|
reset
|
@@ -502,10 +444,8 @@ class Mysql
|
|
502
444
|
end
|
503
445
|
|
504
446
|
# Read one packet data
|
505
|
-
#
|
506
|
-
# [
|
507
|
-
# === Exception
|
508
|
-
# [ProtocolError] invalid packet sequence number
|
447
|
+
# @return [Packet] packet data
|
448
|
+
# @rails [ProtocolError] invalid packet sequence number
|
509
449
|
def read
|
510
450
|
data = ''
|
511
451
|
len = nil
|
@@ -546,9 +486,9 @@ class Mysql
|
|
546
486
|
def read_timeout(len, timeout)
|
547
487
|
return @socket.read(len) if timeout.nil? || timeout == 0
|
548
488
|
result = ''
|
549
|
-
e =
|
489
|
+
e = Time.now + timeout
|
550
490
|
while result.size < len
|
551
|
-
now =
|
491
|
+
now = Time.now
|
552
492
|
raise Errno::ETIMEDOUT if now > e
|
553
493
|
r = @socket.read_nonblock(len - result.size, exception: false)
|
554
494
|
case r
|
@@ -566,8 +506,7 @@ class Mysql
|
|
566
506
|
end
|
567
507
|
|
568
508
|
# Write one packet data
|
569
|
-
#
|
570
|
-
# data :: [String / IO] packet data. If data is nil, write empty packet.
|
509
|
+
# @param data [String, IO, nil] packet data. If data is nil, write empty packet.
|
571
510
|
def write(data)
|
572
511
|
begin
|
573
512
|
@socket.sync = false
|
@@ -593,9 +532,9 @@ class Mysql
|
|
593
532
|
def write_timeout(data, timeout)
|
594
533
|
return @socket.write(data) if timeout.nil? || timeout == 0
|
595
534
|
len = 0
|
596
|
-
e =
|
535
|
+
e = Time.now + timeout
|
597
536
|
while len < data.size
|
598
|
-
now =
|
537
|
+
now = Time.now
|
599
538
|
raise Errno::ETIMEDOUT if now > e
|
600
539
|
l = @socket.write_nonblock(data[len..-1], exception: false)
|
601
540
|
case l
|
@@ -611,17 +550,14 @@ class Mysql
|
|
611
550
|
end
|
612
551
|
|
613
552
|
# Read EOF packet
|
614
|
-
#
|
615
|
-
# [ProtocolError] packet is not EOF
|
553
|
+
# @raise [ProtocolError] packet is not EOF
|
616
554
|
def read_eof_packet
|
617
555
|
raise ProtocolError, "packet is not EOF" unless read.eof?
|
618
556
|
end
|
619
557
|
|
620
558
|
# Send simple command
|
621
|
-
#
|
622
|
-
#
|
623
|
-
# === Return
|
624
|
-
# [String] received data
|
559
|
+
# @param packet :: [String] packet data
|
560
|
+
# @return [String] received data
|
625
561
|
def simple_command(packet)
|
626
562
|
synchronize do
|
627
563
|
reset
|
@@ -831,17 +767,15 @@ class Mysql
|
|
831
767
|
end
|
832
768
|
|
833
769
|
class StmtRawRecord
|
834
|
-
#
|
835
|
-
#
|
836
|
-
#
|
837
|
-
# encoding:: [Encoding]
|
770
|
+
# @param pkt [Packet]
|
771
|
+
# @param fields [Array of Fields]
|
772
|
+
# @param encoding [Encoding]
|
838
773
|
def initialize(packet, fields, encoding)
|
839
774
|
@packet, @fields, @encoding = packet, fields, encoding
|
840
775
|
end
|
841
776
|
|
842
777
|
# Parse statement result packet
|
843
|
-
#
|
844
|
-
# [Array of Object] one record
|
778
|
+
# @return [Array<Object>] one record
|
845
779
|
def parse_record_packet
|
846
780
|
@packet.utiny # skip first byte
|
847
781
|
null_bit_map = @packet.read((@fields.length+7+2)/8).unpack("b*").first
|
@@ -851,7 +785,7 @@ class Mysql
|
|
851
785
|
else
|
852
786
|
unsigned = f.flags & Field::UNSIGNED_FLAG != 0
|
853
787
|
v = Protocol.net2value(@packet, f.type, unsigned)
|
854
|
-
if v.is_a? Numeric or v.is_a?
|
788
|
+
if v.nil? or v.is_a? Numeric or v.is_a? Time
|
855
789
|
v
|
856
790
|
elsif f.type == Field::TYPE_BIT or f.charsetnr == Charset::BINARY_CHARSET_NUMBER
|
857
791
|
Charset.to_binary(v)
|