ruby-mysql 3.0.1 → 4.1.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 +57 -0
- data/README.md +95 -2
- data/lib/mysql/authenticator/caching_sha2_password.rb +3 -2
- data/lib/mysql/authenticator/mysql_native_password.rb +1 -0
- data/lib/mysql/authenticator/sha256_password.rb +1 -0
- data/lib/mysql/authenticator.rb +6 -4
- data/lib/mysql/charset.rb +6 -6
- data/lib/mysql/constants.rb +8 -0
- data/lib/mysql/error.rb +7 -5
- data/lib/mysql/field.rb +95 -0
- data/lib/mysql/packet.rb +6 -5
- data/lib/mysql/protocol.rb +299 -192
- data/lib/mysql/result.rb +212 -0
- data/lib/mysql/stmt.rb +219 -0
- data/lib/mysql.rb +113 -523
- metadata +13 -13
- data/test/test_mysql.rb +0 -1603
- data/test/test_mysql_packet.rb +0 -149
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd37c2f40ef7277952c0be41848abc338e29d3a4e9da3f3eed1d1d8f61407c76
|
4
|
+
data.tar.gz: 754994f1cb1f5e4cb007d5f1a3d81238e626ce8d224aef23c58c8af3d5fd351f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c31c8170682621713905f820a2816377a045b3ba489adc39d3575543483475411bdd7ecead30f806494533dd91819e8e53dad1bd3c090164b80d7600666ea1a4
|
7
|
+
data.tar.gz: 6f59d7638d0f09bd3c21cd34e32cae9e995f26219efc5594b3982b94562a0c3726a1258ebfff5e3b0afbe53764135d96eff0250d57d6d75289f65e3b9957e720
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,60 @@
|
|
1
|
+
## [4.1.0] - 2023-10-08
|
2
|
+
|
3
|
+
- Support geometry column <https://gitlab.com/tmtms/ruby-mysql/-/merge_requests/1>
|
4
|
+
- FIX: If the server is localhost and disconnect the connection, Errno::EPIPE is raised <https://gitlab.com/tmtms/ruby-mysql/-/merge_requests/3> <https://gitlab.com/tmtms/ruby-mysql/-/issues/1>
|
5
|
+
- Allow for existing socket when connecting <https://gitlab.com/tmtms/ruby-mysql/-/merge_requests/2> <https://gitlab.com/tmtms/ruby-mysql/-/merge_requests/5>
|
6
|
+
- add `io` keyword parameter
|
7
|
+
|
8
|
+
## [4.0.0] - 2022-11-09
|
9
|
+
|
10
|
+
### Incompatible changes
|
11
|
+
|
12
|
+
- unsupport MySQL 5.5 and Ruby 2.5
|
13
|
+
- `Mysql::Result#fetch` returns converted values unless `cast` is false
|
14
|
+
- `Mysql::Result#each` always returns records from the beginning
|
15
|
+
- Retrieving a DECIMAL type with a prepared statement returns a `BigDecimal` object instead of `String`
|
16
|
+
- Retrieving a DATE type value with a prepared statement returns a `Date` object instead of `Time`
|
17
|
+
- delete `Mysql#more_results`. use `#more_results?` instead.
|
18
|
+
- remove `Mysql::Result#fetch_field`, `#field_tell`, `#field_seek`, `#fetch_field_direct`, `#fetch_lengths`, `#num_fields`.
|
19
|
+
- error 'command out of sync' is `Mysql::ClientError::CommandOutOfSync` instead of `RuntimeError`.
|
20
|
+
- error 'Authentication requires secure connection' is `Mysql::ClientError::AuthPluginErr` instead of `RuntimeError`.
|
21
|
+
|
22
|
+
### Features
|
23
|
+
|
24
|
+
- `Mysql.default_options` is global options.
|
25
|
+
- `Mysql#connect` option `ssl_mode`: support `SSL_MODE_VERIFY_CA`, `SSL_MODE_VERIFY_IDENTITY`.
|
26
|
+
- `Mysql#connect` option `ssl_context_params`: see `OpenSSL::SSL::SSLContext#set_params`.
|
27
|
+
- `Mysql#connect` option `connect_attrs`.
|
28
|
+
- `Mysql::Stmt#more_results?`, `#next_result`, `#info`.
|
29
|
+
- `Mysql#close` and `Mysql::Stmt#close` read pending packets.
|
30
|
+
- `Mysql#query` and `Mysql::Stmt#execute` option: `return_result` and `yield_null_result`.
|
31
|
+
- support session tracking. See https://dev.mysql.com/doc/refman/8.0/en/session-state-tracking.html
|
32
|
+
- thread safe.
|
33
|
+
- `Mysql#query`, `Mysql::Stmt#execute` option: `auto_store_result`.
|
34
|
+
- add `Mysql::Result#server_status`
|
35
|
+
|
36
|
+
### Fixes
|
37
|
+
|
38
|
+
- When using connection that disconnected from client. error 'MySQL client is not connected' is occured instead of 'MySQL server has gone away'.
|
39
|
+
- When SSL error, `MySQL::ClientError::ServerLost` or `ServerGoneError` is occured instead of `OpenSSL::SSL::SSLError`.
|
40
|
+
- `Mysql#server_version` don't require connection.
|
41
|
+
- use `connect_timeout` instead of `read/write_timeout` on initial negotiation.
|
42
|
+
- enable to changing `local_infile` for established connection.
|
43
|
+
- `Mysql.connect` with host nil ignores parameters
|
44
|
+
- raises `IOError` after `Mysql#close`
|
45
|
+
- Fractional seconds of time types were ignored when retrieving values using prepared statements
|
46
|
+
- `Mysql::Stmt#execute` allows true or false values.
|
47
|
+
|
48
|
+
### Others
|
49
|
+
|
50
|
+
- Mysql#prpare raises Mysql::ClientError if the connection is not connected.
|
51
|
+
- using rubocop
|
52
|
+
- migrate from GitHub to GitLab
|
53
|
+
- ignore Gemfile.lock
|
54
|
+
- use rspec instead of test-unit
|
55
|
+
- using connection parameter from spec/config.rb for testing
|
56
|
+
- split files
|
57
|
+
|
1
58
|
## [3.0.1] - 2022-06-18
|
2
59
|
|
3
60
|
- LICENSE: correct author
|
data/README.md
CHANGED
@@ -2,17 +2,21 @@
|
|
2
2
|
|
3
3
|
## Description
|
4
4
|
|
5
|
-
MySQL
|
5
|
+
ruby-mysql is a MySQL client library.
|
6
|
+
It is written entirely in Ruby.
|
7
|
+
Therefore libmysqlclient is not required and no compilation is required during installation.
|
6
8
|
|
7
9
|
## Installation
|
8
10
|
|
9
|
-
```
|
11
|
+
```ruby
|
10
12
|
gem install ruby-mysql
|
11
13
|
```
|
12
14
|
|
13
15
|
## Synopsis
|
14
16
|
|
15
17
|
```ruby
|
18
|
+
require 'mysql'
|
19
|
+
|
16
20
|
my = Mysql.connect('mysql://username:password@hostname:port/dbname?charset=utf8mb4')
|
17
21
|
my.query("select col1, col2 from tblname").each do |col1, col2|
|
18
22
|
p col1, col2
|
@@ -21,6 +25,95 @@ stmt = my.prepare('insert into tblname (col1,col2) values (?,?)')
|
|
21
25
|
stmt.execute 123, 'abc'
|
22
26
|
```
|
23
27
|
|
28
|
+
## Major incompatibility with 3.0
|
29
|
+
|
30
|
+
### Result values are now converted by default
|
31
|
+
|
32
|
+
| MySQL type | Ruby class |
|
33
|
+
|---------------------|--------------------|
|
34
|
+
| NULL | NilClass |
|
35
|
+
| INT | Integer |
|
36
|
+
| DECIMAL | BigDecimal |
|
37
|
+
| FLOAT, DOUBLE | Float |
|
38
|
+
| DATE | Date |
|
39
|
+
| DATETIME, TIMESTAMP | Time |
|
40
|
+
| TIME | Float (as seconds) |
|
41
|
+
| YEAR | Integer |
|
42
|
+
| CHAR, VARCHAR | String |
|
43
|
+
| BIT | String |
|
44
|
+
| TEXT, BLOB, JSON | String |
|
45
|
+
|
46
|
+
3.0:
|
47
|
+
```ruby
|
48
|
+
pp my.query('select 123,123.45,now(),cast(now() as date)').fetch.map{[_1, _1.class]}
|
49
|
+
#=> [["123", String],
|
50
|
+
# ["123.45", String],
|
51
|
+
# ["2022-11-15 00:17:11", String],
|
52
|
+
# ["2022-11-15", String]]
|
53
|
+
```
|
54
|
+
|
55
|
+
4.0:
|
56
|
+
```ruby
|
57
|
+
pp my.query('select 123,123.45,now(),cast(now() as date)').fetch.map{[_1, _1.class]}
|
58
|
+
#=> [[123, Integer],
|
59
|
+
# [0.12345e3, BigDecimal],
|
60
|
+
# [2022-11-15 00:17:17 +0900, Time],
|
61
|
+
# [#<Date: 2022-11-15 ((2459899j,0s,0n),+0s,2299161j)>, Date]]
|
62
|
+
```
|
63
|
+
|
64
|
+
To specify `cast: false`, you get the same behavior as in 3.0.
|
65
|
+
```ruby
|
66
|
+
my.query('select 123,123.45,now(),cast(now() as date)', cast: false).fetch.map{[_1, _1.class]}
|
67
|
+
#=> [["123", String],
|
68
|
+
# ["123.45", String],
|
69
|
+
# ["2022-11-15 00:19:18", String],
|
70
|
+
# ["2022-11-15", String]]
|
71
|
+
```
|
72
|
+
|
73
|
+
It can also be specified during Mysql.new and Mysql.connect.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
my = Mysql.connect('mysql://user:pass@localhost/', cast: false)
|
77
|
+
```
|
78
|
+
|
79
|
+
Changing mysql.default_options will affect the behavior of subsequently created instances.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
my1 = Mysql.connect('mysql://user:pass@localhost/')
|
83
|
+
Mysql.default_options[:cast] = false
|
84
|
+
my2 = Mysql.connect('mysql://user:pass@localhost/')
|
85
|
+
pp my1.query('select 123,123.45,now(),cast(now() as date)').fetch.map{[_1, _1.class]}
|
86
|
+
#=> [[123, Integer],
|
87
|
+
# [0.12345e3, BigDecimal],
|
88
|
+
# [2022-11-15 00:26:09 +0900, Time],
|
89
|
+
# [#<Date: 2022-11-15 ((2459899j,0s,0n),+0s,2299161j)>, Date]]
|
90
|
+
pp my2.query('select 123,123.45,now(),cast(now() as date)').fetch.map{[_1, _1.class]}
|
91
|
+
#=> [["123", String],
|
92
|
+
# ["123.45", String],
|
93
|
+
# ["2022-11-15 00:26:09", String],
|
94
|
+
# ["2022-11-15", String]]
|
95
|
+
```
|
96
|
+
|
97
|
+
### Mysql::Result#each now always return records from the beginning
|
98
|
+
|
99
|
+
3.0:
|
100
|
+
```ruby
|
101
|
+
res = my.query('select 123 union select 456')
|
102
|
+
res.entries
|
103
|
+
#=> [["123"], ["456"]]
|
104
|
+
res.entries
|
105
|
+
#=> []
|
106
|
+
```
|
107
|
+
|
108
|
+
4.0:
|
109
|
+
```ruby
|
110
|
+
res = my.query('select 123 union select 456')
|
111
|
+
res.entries
|
112
|
+
#=> [[123], [456]]
|
113
|
+
res.entries
|
114
|
+
#=> [[123], [456]]
|
115
|
+
```
|
116
|
+
|
24
117
|
## Copyright
|
25
118
|
|
26
119
|
* Author: TOMITA Masahiro <tommy@tmtm.org>
|
@@ -2,6 +2,7 @@ require 'digest/sha2'
|
|
2
2
|
|
3
3
|
class Mysql
|
4
4
|
class Authenticator
|
5
|
+
# caching_sha2_password
|
5
6
|
class CachingSha2Password
|
6
7
|
# @param protocol [Mysql::Protocol]
|
7
8
|
def initialize(protocol)
|
@@ -29,7 +30,7 @@ class Mysql
|
|
29
30
|
if @protocol.client_flags & CLIENT_SSL != 0
|
30
31
|
@protocol.write passwd+"\0"
|
31
32
|
elsif !@protocol.get_server_public_key
|
32
|
-
raise 'Authentication requires secure connection'
|
33
|
+
raise ClientError::AuthPluginErr, 'Authentication requires secure connection'
|
33
34
|
else
|
34
35
|
@protocol.write "\2" # request public key
|
35
36
|
pkt = @protocol.read
|
@@ -40,7 +41,7 @@ class Mysql
|
|
40
41
|
@protocol.write enc
|
41
42
|
end
|
42
43
|
else
|
43
|
-
raise "invalid auth reply packet: #{data.inspect}"
|
44
|
+
raise ClientError, "invalid auth reply packet: #{data.inspect}"
|
44
45
|
end
|
45
46
|
pkt = @protocol.read
|
46
47
|
end
|
data/lib/mysql/authenticator.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
class Mysql
|
2
|
+
# authenticator
|
2
3
|
class Authenticator
|
3
4
|
@plugins = {}
|
4
5
|
|
@@ -33,10 +34,10 @@ class Mysql
|
|
33
34
|
get(plugin) or raise ClientError, "unknown plugin: #{plugin}"
|
34
35
|
end
|
35
36
|
|
36
|
-
def authenticate(user, passwd, db, scramble, plugin_name)
|
37
|
+
def authenticate(user, passwd, db, scramble, plugin_name, connect_attrs)
|
37
38
|
plugin = (get(plugin_name) || DummyPlugin).new(@protocol)
|
38
39
|
pkt = plugin.authenticate(passwd, scramble) do |hashed|
|
39
|
-
@protocol.write Protocol::AuthenticationPacket.serialize(@protocol.client_flags, 1024**3, @protocol.charset.number, user, hashed, db, plugin.name)
|
40
|
+
@protocol.write Protocol::AuthenticationPacket.serialize(@protocol.client_flags, 1024**3, @protocol.charset.number, user, hashed, db, plugin.name, connect_attrs)
|
40
41
|
end
|
41
42
|
while true
|
42
43
|
res = Protocol::AuthenticationResultPacket.parse(pkt)
|
@@ -55,11 +56,12 @@ class Mysql
|
|
55
56
|
end
|
56
57
|
end
|
57
58
|
else
|
58
|
-
raise ClientError, "invalid packet: #{pkt
|
59
|
+
raise ClientError, "invalid packet: #{pkt}"
|
59
60
|
end
|
60
61
|
end
|
61
62
|
end
|
62
63
|
|
64
|
+
# dummy plugin
|
63
65
|
class DummyPlugin
|
64
66
|
# @param protocol [Mysql::Protocol]
|
65
67
|
def initialize(protocol)
|
@@ -75,7 +77,7 @@ class Mysql
|
|
75
77
|
# @param scramble [String]
|
76
78
|
# @yield [String] hashed password
|
77
79
|
# @return [Mysql::Packet]
|
78
|
-
def authenticate(passwd, scramble)
|
80
|
+
def authenticate(passwd, scramble) # rubocop:disable Lint/UnusedMethodArgument
|
79
81
|
yield ''
|
80
82
|
@protocol.read
|
81
83
|
end
|
data/lib/mysql/charset.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# coding: ascii-8bit
|
2
|
+
|
2
3
|
# Copyright (C) 2008-2012 TOMITA Masahiro
|
3
4
|
# mailto:tommy@tmtm.org
|
4
5
|
|
5
|
-
#
|
6
6
|
class Mysql
|
7
7
|
# @!attribute [r] number
|
8
8
|
# @private
|
@@ -327,14 +327,14 @@ class Mysql
|
|
327
327
|
[307, "utf8mb4", "utf8mb4_ru_0900_as_cs", false],
|
328
328
|
[308, "utf8mb4", "utf8mb4_zh_0900_as_cs", false],
|
329
329
|
[309, "utf8mb4", "utf8mb4_0900_bin", false],
|
330
|
-
]
|
330
|
+
].freeze
|
331
331
|
|
332
332
|
# @private
|
333
|
-
NUMBER_TO_CHARSET = {}
|
333
|
+
NUMBER_TO_CHARSET = {} # rubocop:disable Style/MutableConstant
|
334
334
|
# @private
|
335
|
-
COLLATION_TO_CHARSET = {}
|
335
|
+
COLLATION_TO_CHARSET = {} # rubocop:disable Style/MutableConstant
|
336
336
|
# @private
|
337
|
-
CHARSET_DEFAULT = {}
|
337
|
+
CHARSET_DEFAULT = {} # rubocop:disable Style/MutableConstant
|
338
338
|
CHARSETS.each do |number, csname, clname, default|
|
339
339
|
cs = Charset.new number, csname, clname
|
340
340
|
NUMBER_TO_CHARSET[number] = cs
|
@@ -407,7 +407,7 @@ class Mysql
|
|
407
407
|
"utf8" => Encoding::UTF_8,
|
408
408
|
"utf8mb3" => Encoding::UTF_8,
|
409
409
|
"utf8mb4" => Encoding::UTF_8,
|
410
|
-
}
|
410
|
+
}.freeze
|
411
411
|
|
412
412
|
# @private
|
413
413
|
# @param [String] value
|
data/lib/mysql/constants.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# coding: ascii-8bit
|
2
|
+
|
2
3
|
# Copyright (C) 2003 TOMITA Masahiro
|
3
4
|
# mailto:tommy@tmtm.org
|
4
5
|
|
@@ -168,6 +169,13 @@ class Mysql
|
|
168
169
|
REFRESH_OPTIMIZER_COSTS = 1 << 21
|
169
170
|
REFRESH_PERSIST = 1 << 22
|
170
171
|
|
172
|
+
SESSION_TRACK_SYSTEM_VARIABLES = 0 # Session system variables
|
173
|
+
SESSION_TRACK_SCHEMA = 1 # Current schema
|
174
|
+
SESSION_TRACK_STATE_CHANGE = 2 # track session state changes
|
175
|
+
SESSION_TRACK_GTIDS = 3 # See also: session_track_gtids
|
176
|
+
SESSION_TRACK_TRANSACTION_CHARACTERISTICS = 4 # Transaction chistics
|
177
|
+
SESSION_TRACK_TRANSACTION_STATE = 5 # Transaction state
|
178
|
+
|
171
179
|
class Field
|
172
180
|
# Field type
|
173
181
|
TYPE_DECIMAL = 0
|
data/lib/mysql/error.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
# coding: ascii-8bit
|
2
|
+
|
2
3
|
# Copyright (C) 2003-2010 TOMITA Masahiro
|
3
4
|
# mailto:tommy@tmtm.org
|
4
5
|
|
6
|
+
# Mysql
|
5
7
|
class Mysql
|
8
|
+
# Mysql::Error
|
6
9
|
class Error < StandardError
|
7
10
|
ERRNO = 0
|
8
11
|
|
@@ -11,7 +14,7 @@ class Mysql
|
|
11
14
|
errname = errname.to_s
|
12
15
|
next unless errname =~ prefix_re
|
13
16
|
errno = self.const_get errname
|
14
|
-
excname = errname.sub(prefix_re,'').gsub(/(\A.|_.)([A-Z]+)/){$1+$2.downcase}.gsub(/_/,'')
|
17
|
+
excname = errname.sub(prefix_re, '').gsub(/(\A.|_.)([A-Z]+)/){$1+$2.downcase}.gsub(/_/, '')
|
15
18
|
klass = Class.new self
|
16
19
|
klass.const_set 'ERRNO', errno
|
17
20
|
self.const_set excname, klass
|
@@ -32,7 +35,7 @@ class Mysql
|
|
32
35
|
|
33
36
|
# server side error
|
34
37
|
class ServerError < Error
|
35
|
-
ERROR_MAP = {}
|
38
|
+
ERROR_MAP = {} # rubocop:disable Style/MutableConstant
|
36
39
|
|
37
40
|
ER_ERROR_FIRST = 1000
|
38
41
|
ER_HASHCHK = 1000
|
@@ -905,11 +908,11 @@ class Mysql
|
|
905
908
|
end
|
906
909
|
|
907
910
|
ServerError.define_error_class(/\AER_/)
|
908
|
-
ServerError::ERROR_MAP.
|
911
|
+
ServerError::ERROR_MAP.each_value{|v| Mysql.const_set v.name.split(/::/).last, v} # for compatibility
|
909
912
|
|
910
913
|
# client side error
|
911
914
|
class ClientError < Error
|
912
|
-
ERROR_MAP = {}
|
915
|
+
ERROR_MAP = {} # rubocop:disable Style/MutableConstant
|
913
916
|
|
914
917
|
CR_ERROR_FIRST = 2000
|
915
918
|
CR_UNKNOWN_ERROR = 2000
|
@@ -991,5 +994,4 @@ class Mysql
|
|
991
994
|
# protocol error
|
992
995
|
class ProtocolError < ClientError
|
993
996
|
end
|
994
|
-
|
995
997
|
end
|
data/lib/mysql/field.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
class Mysql
|
2
|
+
# @!visibility public
|
3
|
+
# Field class
|
4
|
+
class Field
|
5
|
+
# @return [String] database name
|
6
|
+
attr_reader :db
|
7
|
+
# @return [String] table name
|
8
|
+
attr_reader :table
|
9
|
+
# @return [String] original table name
|
10
|
+
attr_reader :org_table
|
11
|
+
# @return [String] field name
|
12
|
+
attr_reader :name
|
13
|
+
# @return [String] original field name
|
14
|
+
attr_reader :org_name
|
15
|
+
# @return [Integer] charset id number
|
16
|
+
attr_reader :charsetnr
|
17
|
+
# @return [Integer] field length
|
18
|
+
attr_reader :length
|
19
|
+
# @return [Integer] field type
|
20
|
+
attr_reader :type
|
21
|
+
# @return [Integer] flag
|
22
|
+
attr_reader :flags
|
23
|
+
# @return [Integer] number of decimals
|
24
|
+
attr_reader :decimals
|
25
|
+
# @return [String] defualt value
|
26
|
+
attr_reader :default
|
27
|
+
alias def default
|
28
|
+
|
29
|
+
# @private
|
30
|
+
attr_accessor :result
|
31
|
+
|
32
|
+
# @attr [Protocol::FieldPacket] packet
|
33
|
+
def initialize(packet)
|
34
|
+
@db, @table, @org_table, @name, @org_name, @charsetnr, @length, @type, @flags, @decimals, @default =
|
35
|
+
packet.db, packet.table, packet.org_table, packet.name, packet.org_name, packet.charsetnr, packet.length, packet.type, packet.flags, packet.decimals, packet.default
|
36
|
+
@db.force_encoding('utf-8')
|
37
|
+
@table.force_encoding('utf-8')
|
38
|
+
@org_table.force_encoding('utf-8')
|
39
|
+
@name.force_encoding('utf-8')
|
40
|
+
@org_name.force_encoding('utf-8')
|
41
|
+
@flags |= NUM_FLAG if is_num_type?
|
42
|
+
@max_length = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Hash] field information
|
46
|
+
def to_hash
|
47
|
+
{
|
48
|
+
"name" => @name,
|
49
|
+
"table" => @table,
|
50
|
+
"def" => @default,
|
51
|
+
"type" => @type,
|
52
|
+
"length" => @length,
|
53
|
+
"max_length" => max_length,
|
54
|
+
"flags" => @flags,
|
55
|
+
"decimals" => @decimals,
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
# @private
|
60
|
+
def inspect
|
61
|
+
"#<Mysql::Field:#{@name}>"
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [Boolean] true if numeric field.
|
65
|
+
def is_num?
|
66
|
+
@flags & NUM_FLAG != 0
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [Boolean] true if not null field.
|
70
|
+
def is_not_null?
|
71
|
+
@flags & NOT_NULL_FLAG != 0
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [Boolean] true if primary key field.
|
75
|
+
def is_pri_key?
|
76
|
+
@flags & PRI_KEY_FLAG != 0
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [Integer] maximum width of the field for the result set
|
80
|
+
def max_length
|
81
|
+
return @max_length if @max_length
|
82
|
+
@max_length = 0
|
83
|
+
@result&.calculate_field_max_length
|
84
|
+
@max_length
|
85
|
+
end
|
86
|
+
|
87
|
+
attr_writer :max_length
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def is_num_type?
|
92
|
+
[TYPE_DECIMAL, TYPE_TINY, TYPE_SHORT, TYPE_LONG, TYPE_FLOAT, TYPE_DOUBLE, TYPE_LONGLONG, TYPE_INT24].include?(@type) || (@type == TYPE_TIMESTAMP && (@length == 14 || @length == 8))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/mysql/packet.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# coding: ascii-8bit
|
2
|
+
|
2
3
|
class Mysql
|
4
|
+
# Mysql::Packet
|
3
5
|
class Packet
|
4
6
|
# convert Numeric to LengthCodedBinary
|
5
7
|
def self.lcb(num)
|
@@ -49,21 +51,21 @@ class Mysql
|
|
49
51
|
end
|
50
52
|
|
51
53
|
def string
|
52
|
-
str = @data.
|
54
|
+
str = @data.unpack1('Z*')
|
53
55
|
@data.slice!(0, str.length+1)
|
54
56
|
str
|
55
57
|
end
|
56
58
|
|
57
59
|
def utiny
|
58
|
-
@data.slice!(0, 1).
|
60
|
+
@data.slice!(0, 1).unpack1('C')
|
59
61
|
end
|
60
62
|
|
61
63
|
def ushort
|
62
|
-
@data.slice!(0, 2).
|
64
|
+
@data.slice!(0, 2).unpack1('v')
|
63
65
|
end
|
64
66
|
|
65
67
|
def ulong
|
66
|
-
@data.slice!(0, 4).
|
68
|
+
@data.slice!(0, 4).unpack1('V')
|
67
69
|
end
|
68
70
|
|
69
71
|
def eof?
|
@@ -73,6 +75,5 @@ class Mysql
|
|
73
75
|
def to_s
|
74
76
|
@data
|
75
77
|
end
|
76
|
-
|
77
78
|
end
|
78
79
|
end
|