ruby-mysql 2.11.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|