ruby-mysql 2.9.11 → 2.10.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 +5 -5
- data/README.rdoc +5 -2
- data/lib/mysql/charset.rb +225 -153
- data/lib/mysql/constants.rb +147 -70
- data/lib/mysql/error.rb +10 -1
- data/lib/mysql/protocol.rb +47 -50
- data/lib/mysql.rb +10 -8
- data/test/test_mysql.rb +1886 -0
- data/test/test_mysql_packet.rb +149 -0
- metadata +15 -17
- data/spec/mysql/packet_spec.rb +0 -118
- data/spec/mysql_spec.rb +0 -1789
data/lib/mysql/constants.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# coding: ascii-8bit
|
2
|
-
# Copyright (C) 2003
|
2
|
+
# Copyright (C) 2003 TOMITA Masahiro
|
3
3
|
# mailto:tommy@tmtm.org
|
4
4
|
|
5
5
|
class Mysql
|
@@ -33,50 +33,88 @@ class Mysql
|
|
33
33
|
COM_STMT_RESET = 26
|
34
34
|
COM_SET_OPTION = 27
|
35
35
|
COM_STMT_FETCH = 28
|
36
|
+
COM_DAEMON = 29
|
37
|
+
COM_BINLOG_DUMP_GTID = 30
|
38
|
+
COM_RESET_CONNECTION = 31
|
39
|
+
COM_CLONE = 32
|
36
40
|
|
37
41
|
# Client flag
|
38
|
-
CLIENT_LONG_PASSWORD
|
39
|
-
CLIENT_FOUND_ROWS
|
40
|
-
CLIENT_LONG_FLAG
|
41
|
-
CLIENT_CONNECT_WITH_DB
|
42
|
-
CLIENT_NO_SCHEMA
|
43
|
-
CLIENT_COMPRESS
|
44
|
-
CLIENT_ODBC
|
45
|
-
CLIENT_LOCAL_FILES
|
46
|
-
CLIENT_IGNORE_SPACE
|
47
|
-
CLIENT_PROTOCOL_41
|
48
|
-
CLIENT_INTERACTIVE
|
49
|
-
CLIENT_SSL
|
50
|
-
CLIENT_IGNORE_SIGPIPE
|
51
|
-
CLIENT_TRANSACTIONS
|
52
|
-
CLIENT_RESERVED
|
53
|
-
CLIENT_SECURE_CONNECTION
|
54
|
-
CLIENT_MULTI_STATEMENTS
|
55
|
-
CLIENT_MULTI_RESULTS
|
42
|
+
CLIENT_LONG_PASSWORD = 1 # new more secure passwords
|
43
|
+
CLIENT_FOUND_ROWS = 1 << 1 # Found instead of affected rows
|
44
|
+
CLIENT_LONG_FLAG = 1 << 2 # Get all column flags
|
45
|
+
CLIENT_CONNECT_WITH_DB = 1 << 3 # One can specify db on connect
|
46
|
+
CLIENT_NO_SCHEMA = 1 << 4 # Don't allow database.table.column
|
47
|
+
CLIENT_COMPRESS = 1 << 5 # Can use compression protocol
|
48
|
+
CLIENT_ODBC = 1 << 6 # Odbc client
|
49
|
+
CLIENT_LOCAL_FILES = 1 << 7 # Can use LOAD DATA LOCAL
|
50
|
+
CLIENT_IGNORE_SPACE = 1 << 8 # Ignore spaces before '('
|
51
|
+
CLIENT_PROTOCOL_41 = 1 << 9 # New 4.1 protocol
|
52
|
+
CLIENT_INTERACTIVE = 1 << 10 # This is an interactive client
|
53
|
+
CLIENT_SSL = 1 << 11 # Switch to SSL after handshake
|
54
|
+
CLIENT_IGNORE_SIGPIPE = 1 << 12 # IGNORE sigpipes
|
55
|
+
CLIENT_TRANSACTIONS = 1 << 13 # Client knows about transactions
|
56
|
+
CLIENT_RESERVED = 1 << 14 # Old flag for 4.1 protocol
|
57
|
+
CLIENT_SECURE_CONNECTION = 1 << 15 # New 4.1 authentication
|
58
|
+
CLIENT_MULTI_STATEMENTS = 1 << 16 # Enable/disable multi-stmt support
|
59
|
+
CLIENT_MULTI_RESULTS = 1 << 17 # Enable/disable multi-results
|
60
|
+
CLIENT_PS_MULTI_RESULTS = 1 << 18 # Multi-results in PS-protocol
|
61
|
+
CLIENT_PLUGIN_AUTH = 1 << 19 # Client supports plugin authentication
|
62
|
+
CLIENT_CONNECT_ATTRS = 1 << 20 # Client supports connection attribute
|
63
|
+
CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA = 1 << 21 # Enable authentication response packet to be larger than 255 bytes.
|
64
|
+
CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS = 1 << 22 # Don't close the connection for a connection with expired password.
|
65
|
+
CLIENT_SESSION_TRACK = 1 << 23 # Capable of handling server state change information. Its a hint to the server to include the state change information in Ok packet.
|
66
|
+
CLIENT_DEPRECATE_EOF = 1 << 24 # Client no longer needs EOF packet
|
67
|
+
CLIENT_OPTIONAL_RESULTSET_METADATA = 1 << 25 # The client can handle optional metadata information in the resultset.
|
68
|
+
CLIENT_ZSTD_COMPRESSION_ALGORITHM = 1 << 26 # Compression protocol extended to support zstd compression method
|
69
|
+
CLIENT_CAPABILITY_EXTENSION = 1 << 29 # This flag will be reserved to extend the 32bit capabilities structure to 64bits.
|
70
|
+
CLIENT_SSL_VERIFY_SERVER_CERT = 1 << 30 # Verify server certificate.
|
71
|
+
CLIENT_REMEMBER_OPTIONS = 1 << 31 # Don't reset the options after an unsuccessful connect
|
56
72
|
|
57
73
|
# Connection Option
|
58
|
-
OPT_CONNECT_TIMEOUT
|
59
|
-
OPT_COMPRESS
|
60
|
-
OPT_NAMED_PIPE
|
61
|
-
INIT_COMMAND
|
62
|
-
READ_DEFAULT_FILE
|
63
|
-
READ_DEFAULT_GROUP
|
64
|
-
SET_CHARSET_DIR
|
65
|
-
SET_CHARSET_NAME
|
66
|
-
OPT_LOCAL_INFILE
|
67
|
-
OPT_PROTOCOL
|
68
|
-
SHARED_MEMORY_BASE_NAME
|
69
|
-
OPT_READ_TIMEOUT
|
70
|
-
OPT_WRITE_TIMEOUT
|
71
|
-
OPT_USE_RESULT
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
74
|
+
OPT_CONNECT_TIMEOUT = 0
|
75
|
+
OPT_COMPRESS = 1
|
76
|
+
OPT_NAMED_PIPE = 2
|
77
|
+
INIT_COMMAND = 3
|
78
|
+
READ_DEFAULT_FILE = 4
|
79
|
+
READ_DEFAULT_GROUP = 5
|
80
|
+
SET_CHARSET_DIR = 6
|
81
|
+
SET_CHARSET_NAME = 7
|
82
|
+
OPT_LOCAL_INFILE = 8
|
83
|
+
OPT_PROTOCOL = 9
|
84
|
+
SHARED_MEMORY_BASE_NAME = 10
|
85
|
+
OPT_READ_TIMEOUT = 11
|
86
|
+
OPT_WRITE_TIMEOUT = 12
|
87
|
+
OPT_USE_RESULT = 13
|
88
|
+
REPORT_DATA_TRUNCATION = 14
|
89
|
+
OPT_RECONNECT = 15
|
90
|
+
PLUGIN_DIR = 16
|
91
|
+
DEFAULT_AUTH = 17
|
92
|
+
OPT_BIND = 18
|
93
|
+
OPT_SSL_KEY = 19
|
94
|
+
OPT_SSL_CERT = 20
|
95
|
+
OPT_SSL_CA = 21
|
96
|
+
OPT_SSL_CAPATH = 22
|
97
|
+
OPT_SSL_CIPHER = 23
|
98
|
+
OPT_SSL_CRL = 24
|
99
|
+
OPT_SSL_CRLPATH = 25
|
100
|
+
OPT_CONNECT_ATTR_RESET = 26
|
101
|
+
OPT_CONNECT_ATTR_ADD = 27
|
102
|
+
OPT_CONNECT_ATTR_DELETE = 28
|
103
|
+
SERVER_PUBLIC_KEY = 29
|
104
|
+
ENABLE_CLEARTEXT_PLUGIN = 30
|
105
|
+
OPT_CAN_HANDLE_EXPIRED_PASSWORDS = 31
|
106
|
+
OPT_MAX_ALLOWED_PACKET = 32
|
107
|
+
OPT_NET_BUFFER_LENGTH = 33
|
108
|
+
OPT_TLS_VERSION = 34
|
109
|
+
OPT_SSL_MODE = 35
|
110
|
+
OPT_GET_SERVER_PUBLIC_KEY = 36
|
111
|
+
OPT_RETRY_COUNT = 37
|
112
|
+
OPT_OPTIONAL_RESULTSET_METADATA = 38
|
113
|
+
OPT_SSL_FIPS_MODE = 39
|
114
|
+
OPT_TLS_CIPHERSUITES = 40
|
115
|
+
OPT_COMPRESSION_ALGORITHMS = 41
|
116
|
+
OPT_ZSTD_COMPRESSION_LEVEL = 42
|
117
|
+
OPT_LOAD_DATA_LOCAL_DIR = 43
|
80
118
|
|
81
119
|
# Server Option
|
82
120
|
OPTION_MULTI_STATEMENTS_ON = 0
|
@@ -92,18 +130,36 @@ class Mysql
|
|
92
130
|
SERVER_STATUS_LAST_ROW_SENT = 1 << 7
|
93
131
|
SERVER_STATUS_DB_DROPPED = 1 << 8
|
94
132
|
SERVER_STATUS_NO_BACKSLASH_ESCAPES = 1 << 9
|
133
|
+
SERVER_STATUS_METADATA_CHANGED = 1 << 10
|
134
|
+
SERVER_QUERY_WAS_SLOW = 1 << 11
|
135
|
+
SERVER_PS_OUT_PARAMS = 1 << 12
|
136
|
+
SERVER_STATUS_IN_TRANS_READONLY = 1 << 13
|
137
|
+
SERVER_SESSION_STATE_CHANGED = 1 << 14
|
95
138
|
|
96
139
|
# Refresh parameter
|
97
|
-
REFRESH_GRANT
|
98
|
-
REFRESH_LOG
|
99
|
-
REFRESH_TABLES
|
100
|
-
REFRESH_HOSTS
|
101
|
-
REFRESH_STATUS
|
102
|
-
REFRESH_THREADS
|
103
|
-
REFRESH_SLAVE
|
104
|
-
REFRESH_MASTER
|
105
|
-
|
106
|
-
|
140
|
+
REFRESH_GRANT = 1
|
141
|
+
REFRESH_LOG = 1 << 1
|
142
|
+
REFRESH_TABLES = 1 << 2
|
143
|
+
REFRESH_HOSTS = 1 << 3
|
144
|
+
REFRESH_STATUS = 1 << 4
|
145
|
+
REFRESH_THREADS = 1 << 5
|
146
|
+
REFRESH_SLAVE = 1 << 6
|
147
|
+
REFRESH_MASTER = 1 << 7
|
148
|
+
REFRESH_ERROR_LOG = 1 << 8
|
149
|
+
REFRESH_ENGINE_LOG = 1 << 9
|
150
|
+
REFRESH_BINARY_LOG = 1 << 10
|
151
|
+
REFRESH_RELAY_LOG = 1 << 11
|
152
|
+
REFRESH_GENERAL_LOG = 1 << 12
|
153
|
+
REFRESH_SLOW_LOG = 1 << 13
|
154
|
+
REFRESH_READ_LOCK = 1 << 14
|
155
|
+
REFRESH_FAST = 1 << 15
|
156
|
+
REFRESH_QUERY_CACHE = 1 << 16
|
157
|
+
REFRESH_QUERY_CACHE_FREE = 1 << 17
|
158
|
+
REFRESH_DES_KEY_FILE = 1 << 18
|
159
|
+
REFRESH_USER_RESOURCES = 1 << 19
|
160
|
+
REFRESH_FOR_EXPORT = 1 << 20
|
161
|
+
REFRESH_OPTIMIZER_COSTS = 1 << 21
|
162
|
+
REFRESH_PERSIST = 1 << 22
|
107
163
|
|
108
164
|
class Field
|
109
165
|
# Field type
|
@@ -124,6 +180,13 @@ class Mysql
|
|
124
180
|
TYPE_NEWDATE = 14
|
125
181
|
TYPE_VARCHAR = 15
|
126
182
|
TYPE_BIT = 16
|
183
|
+
TYPE_TIMESTAMP2 = 17
|
184
|
+
TYPE_DATETIME2 = 18
|
185
|
+
TYPE_TIME2 = 19
|
186
|
+
TYPE_TYPED_ARRAY = 20
|
187
|
+
TYPE_INVALID = 243
|
188
|
+
TYPE_BOOL = 244
|
189
|
+
TYPE_JSON = 245
|
127
190
|
TYPE_NEWDECIMAL = 246
|
128
191
|
TYPE_ENUM = 247
|
129
192
|
TYPE_SET = 248
|
@@ -138,28 +201,42 @@ class Mysql
|
|
138
201
|
TYPE_INTERVAL = TYPE_ENUM
|
139
202
|
|
140
203
|
# Flag
|
141
|
-
NOT_NULL_FLAG
|
142
|
-
PRI_KEY_FLAG
|
143
|
-
UNIQUE_KEY_FLAG
|
144
|
-
MULTIPLE_KEY_FLAG
|
145
|
-
BLOB_FLAG
|
146
|
-
UNSIGNED_FLAG
|
147
|
-
ZEROFILL_FLAG
|
148
|
-
BINARY_FLAG
|
149
|
-
ENUM_FLAG
|
150
|
-
AUTO_INCREMENT_FLAG
|
151
|
-
TIMESTAMP_FLAG
|
152
|
-
SET_FLAG
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
204
|
+
NOT_NULL_FLAG = 1
|
205
|
+
PRI_KEY_FLAG = 2
|
206
|
+
UNIQUE_KEY_FLAG = 4
|
207
|
+
MULTIPLE_KEY_FLAG = 8
|
208
|
+
BLOB_FLAG = 16
|
209
|
+
UNSIGNED_FLAG = 32
|
210
|
+
ZEROFILL_FLAG = 64
|
211
|
+
BINARY_FLAG = 128
|
212
|
+
ENUM_FLAG = 256
|
213
|
+
AUTO_INCREMENT_FLAG = 512
|
214
|
+
TIMESTAMP_FLAG = 1024
|
215
|
+
SET_FLAG = 2048
|
216
|
+
NO_DEFAULT_VALUE_FLAG = 4096
|
217
|
+
ON_UPDATE_NOW_FLAG = 8192
|
218
|
+
NUM_FLAG = 32768
|
219
|
+
PART_KEY_FLAG = 16384
|
220
|
+
GROUP_FLAG = 32768
|
221
|
+
UNIQUE_FLAG = 65536
|
222
|
+
BINCMP_FLAG = 131072
|
223
|
+
GET_FIXED_FIELDS_FLAG = 1 << 18
|
224
|
+
FIELD_IN_PART_FUNC_FLAG = 1 << 19
|
225
|
+
FIELD_IN_ADD_INDEX = 1 << 20
|
226
|
+
FIELD_IS_RENAMED = 1 << 21
|
227
|
+
FIELD_FLAGS_STORAGE_MEDIA_MASK = 3 << 22
|
228
|
+
FIELD_FLAGS_COLUMN_FORMAT_MASK = 3 << 24
|
229
|
+
FIELD_IS_DROPPED = 1 << 26
|
230
|
+
EXPLICIT_NULL_FLAG = 1 << 27
|
231
|
+
FIELD_IS_MARKED = 1 << 28
|
232
|
+
NOT_SECONDARY_FLAG = 1 << 29
|
158
233
|
end
|
159
234
|
|
160
235
|
class Stmt
|
161
236
|
# Cursor type
|
162
|
-
CURSOR_TYPE_NO_CURSOR
|
163
|
-
CURSOR_TYPE_READ_ONLY
|
237
|
+
CURSOR_TYPE_NO_CURSOR = 0
|
238
|
+
CURSOR_TYPE_READ_ONLY = 1
|
239
|
+
CURSOR_TYPE_FOR_UPDATE = 2
|
240
|
+
CURSOR_TYPE_SCROLLABLE = 4
|
164
241
|
end
|
165
242
|
end
|
data/lib/mysql/error.rb
CHANGED
@@ -977,7 +977,16 @@ class Mysql
|
|
977
977
|
CR_AUTH_PLUGIN_CANNOT_LOAD = 2059
|
978
978
|
CR_DUPLICATE_CONNECTION_ATTR = 2060
|
979
979
|
CR_AUTH_PLUGIN_ERR = 2061
|
980
|
-
|
980
|
+
CR_INSECURE_API_ERR = 2062
|
981
|
+
CR_FILE_NAME_TOO_LONG = 2063
|
982
|
+
CR_SSL_FIPS_MODE_ERR = 2064
|
983
|
+
CR_DEPRECATED_COMPRESSION_NOT_SUPPORTED = 2065
|
984
|
+
CR_COMPRESSION_WRONGLY_CONFIGURED = 2066
|
985
|
+
CR_KERBEROS_USER_NOT_FOUND = 2067
|
986
|
+
CR_LOAD_DATA_LOCAL_INFILE_REJECTED = 2068
|
987
|
+
CR_LOAD_DATA_LOCAL_INFILE_REALPATH_FAIL = 2069
|
988
|
+
CR_DNS_SRV_LOOKUP_FAILED = 2070
|
989
|
+
CR_ERROR_LAST = 2070
|
981
990
|
end
|
982
991
|
|
983
992
|
ClientError.define_error_class(/\ACR_/)
|
data/lib/mysql/protocol.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# coding: ascii-8bit
|
2
|
-
# Copyright (C) 2008
|
2
|
+
# Copyright (C) 2008 TOMITA Masahiro
|
3
3
|
# mailto:tommy@tmtm.org
|
4
4
|
|
5
5
|
require "socket"
|
@@ -23,7 +23,7 @@ class Mysql
|
|
23
23
|
# Object :: converted value.
|
24
24
|
def self.net2value(pkt, type, unsigned)
|
25
25
|
case type
|
26
|
-
when Field::TYPE_STRING, Field::TYPE_VAR_STRING, Field::TYPE_NEWDECIMAL, Field::TYPE_BLOB
|
26
|
+
when Field::TYPE_STRING, Field::TYPE_VAR_STRING, Field::TYPE_NEWDECIMAL, Field::TYPE_BLOB, Field::TYPE_JSON
|
27
27
|
return pkt.lcs
|
28
28
|
when Field::TYPE_TINY
|
29
29
|
v = pkt.utiny
|
@@ -33,11 +33,11 @@ class Mysql
|
|
33
33
|
return unsigned ? v : v < 32768 ? v : v-65536
|
34
34
|
when Field::TYPE_INT24, Field::TYPE_LONG
|
35
35
|
v = pkt.ulong
|
36
|
-
return unsigned ? v : v <
|
36
|
+
return unsigned ? v : v < 0x8000_0000 ? v : v-0x10000_0000
|
37
37
|
when Field::TYPE_LONGLONG
|
38
38
|
n1, n2 = pkt.ulong, pkt.ulong
|
39
39
|
v = (n2 << 32) | n1
|
40
|
-
return unsigned ? v : v <
|
40
|
+
return unsigned ? v : v < 0x8000_0000_0000_0000 ? v : v-0x10000_0000_0000_0000
|
41
41
|
when Field::TYPE_FLOAT
|
42
42
|
return pkt.read(4).unpack('e').first
|
43
43
|
when Field::TYPE_DOUBLE
|
@@ -79,38 +79,17 @@ class Mysql
|
|
79
79
|
type = Field::TYPE_NULL
|
80
80
|
val = ""
|
81
81
|
when Integer
|
82
|
-
if v
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
val = [v].pack("V")
|
92
|
-
elsif v < 256**8
|
93
|
-
type = Field::TYPE_LONGLONG | 0x8000
|
94
|
-
val = [v&0xffffffff, v>>32].pack("VV")
|
95
|
-
else
|
96
|
-
raise ProtocolError, "value too large: #{v}"
|
97
|
-
end
|
82
|
+
if -0x8000_0000 <= v && v < 0x8000_0000
|
83
|
+
type = Field::TYPE_LONG
|
84
|
+
val = [v].pack('V')
|
85
|
+
elsif -0x8000_0000_0000_0000 <= v && v < 0x8000_0000_0000_0000
|
86
|
+
type = Field::TYPE_LONGLONG
|
87
|
+
val = [v&0xffffffff, v>>32].pack("VV")
|
88
|
+
elsif 0x8000_0000_0000_0000 <= v && v <= 0xffff_ffff_ffff_ffff
|
89
|
+
type = Field::TYPE_LONGLONG | 0x8000
|
90
|
+
val = [v&0xffffffff, v>>32].pack("VV")
|
98
91
|
else
|
99
|
-
|
100
|
-
type = Field::TYPE_TINY
|
101
|
-
val = [v].pack("C")
|
102
|
-
elsif -v <= 256**2/2
|
103
|
-
type = Field::TYPE_SHORT
|
104
|
-
val = [v].pack("v")
|
105
|
-
elsif -v <= 256**4/2
|
106
|
-
type = Field::TYPE_LONG
|
107
|
-
val = [v].pack("V")
|
108
|
-
elsif -v <= 256**8/2
|
109
|
-
type = Field::TYPE_LONGLONG
|
110
|
-
val = [v&0xffffffff, v>>32].pack("VV")
|
111
|
-
else
|
112
|
-
raise ProtocolError, "value too large: #{v}"
|
113
|
-
end
|
92
|
+
raise ProtocolError, "value too large: #{v}"
|
114
93
|
end
|
115
94
|
when Float
|
116
95
|
type = Field::TYPE_DOUBLE
|
@@ -118,9 +97,12 @@ class Mysql
|
|
118
97
|
when String
|
119
98
|
type = Field::TYPE_STRING
|
120
99
|
val = Packet.lcs(v)
|
121
|
-
when
|
100
|
+
when ::Time
|
101
|
+
type = Field::TYPE_DATETIME
|
102
|
+
val = [11, v.year, v.month, v.day, v.hour, v.min, v.sec, v.usec].pack("CvCCCCCV")
|
103
|
+
when Mysql::Time
|
122
104
|
type = Field::TYPE_DATETIME
|
123
|
-
val = [
|
105
|
+
val = [11, v.year, v.month, v.day, v.hour, v.min, v.sec, v.second_part].pack("CvCCCCCV")
|
124
106
|
else
|
125
107
|
raise ProtocolError, "class #{v.class} is not supported"
|
126
108
|
end
|
@@ -152,15 +134,17 @@ class Mysql
|
|
152
134
|
# conn_timeout :: [Integer] connect timeout (sec).
|
153
135
|
# read_timeout :: [Integer] read timeout (sec).
|
154
136
|
# write_timeout :: [Integer] write timeout (sec).
|
137
|
+
# local_infile :: [String] local infile path
|
155
138
|
# === Exception
|
156
139
|
# [ClientError] :: connection timeout
|
157
|
-
def initialize(host, port, socket, conn_timeout, read_timeout, write_timeout)
|
140
|
+
def initialize(host, port, socket, conn_timeout, read_timeout, write_timeout, local_infile)
|
158
141
|
@insert_id = 0
|
159
142
|
@warning_count = 0
|
160
143
|
@gc_stmt_queue = [] # stmt id list which GC destroy.
|
161
144
|
set_state :INIT
|
162
145
|
@read_timeout = read_timeout
|
163
146
|
@write_timeout = write_timeout
|
147
|
+
@local_infile = local_infile
|
164
148
|
begin
|
165
149
|
Timeout.timeout conn_timeout do
|
166
150
|
if host.nil? or host.empty? or host == "localhost"
|
@@ -198,6 +182,7 @@ class Mysql
|
|
198
182
|
@server_version = init_packet.server_version.split(/\D/)[0,3].inject{|a,b|a.to_i*100+b.to_i}
|
199
183
|
@thread_id = init_packet.thread_id
|
200
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
|
201
186
|
client_flags |= CLIENT_CONNECT_WITH_DB if db
|
202
187
|
client_flags |= flag
|
203
188
|
@charset = charset
|
@@ -248,10 +233,7 @@ class Mysql
|
|
248
233
|
return res_packet.field_count
|
249
234
|
end
|
250
235
|
if res_packet.field_count.nil? # LOAD DATA LOCAL INFILE
|
251
|
-
|
252
|
-
File.open(filename){|f| write f}
|
253
|
-
write nil # EOF mark
|
254
|
-
read
|
236
|
+
send_local_file(res_packet.message)
|
255
237
|
end
|
256
238
|
@affected_rows, @insert_id, @server_status, @warning_count, @message =
|
257
239
|
res_packet.affected_rows, res_packet.insert_id, res_packet.server_status, res_packet.warning_count, res_packet.message
|
@@ -263,6 +245,19 @@ class Mysql
|
|
263
245
|
end
|
264
246
|
end
|
265
247
|
|
248
|
+
# send local file to server
|
249
|
+
def send_local_file(filename)
|
250
|
+
filename = File.absolute_path(filename)
|
251
|
+
if filename.start_with? @local_infile
|
252
|
+
File.open(filename){|f| write f}
|
253
|
+
else
|
254
|
+
raise ClientError::LoadDataLocalInfileRejected, 'LOAD DATA LOCAL INFILE file request rejected due to restrictions on access.'
|
255
|
+
end
|
256
|
+
ensure
|
257
|
+
write nil # EOF mark
|
258
|
+
read
|
259
|
+
end
|
260
|
+
|
266
261
|
# Retrieve n fields
|
267
262
|
# === Argument
|
268
263
|
# n :: [Integer] number of fields
|
@@ -488,7 +483,7 @@ class Mysql
|
|
488
483
|
# === Exception
|
489
484
|
# [ProtocolError] invalid packet sequence number
|
490
485
|
def read
|
491
|
-
|
486
|
+
data = ''
|
492
487
|
len = nil
|
493
488
|
begin
|
494
489
|
Timeout.timeout @read_timeout do
|
@@ -500,6 +495,7 @@ class Mysql
|
|
500
495
|
@seq = (@seq + 1) % 256
|
501
496
|
ret = @sock.read(len)
|
502
497
|
raise EOFError unless ret && ret.length == len
|
498
|
+
data.concat ret
|
503
499
|
end
|
504
500
|
rescue EOFError
|
505
501
|
raise ClientError::ServerGoneError, 'MySQL server has gone away'
|
@@ -510,18 +506,19 @@ class Mysql
|
|
510
506
|
@sqlstate = "00000"
|
511
507
|
|
512
508
|
# Error packet
|
513
|
-
if
|
514
|
-
f, errno, marker, @sqlstate, message =
|
509
|
+
if data[0] == ?\xff
|
510
|
+
f, errno, marker, @sqlstate, message = data.unpack("Cvaa5a*")
|
515
511
|
unless marker == "#"
|
516
|
-
f, errno, message =
|
512
|
+
f, errno, message = data.unpack("Cva*") # Version 4.0 Error
|
517
513
|
@sqlstate = ""
|
518
514
|
end
|
515
|
+
message.force_encoding(@charset.encoding)
|
519
516
|
if Mysql::ServerError::ERROR_MAP.key? errno
|
520
517
|
raise Mysql::ServerError::ERROR_MAP[errno].new(message, @sqlstate)
|
521
518
|
end
|
522
519
|
raise Mysql::ServerError.new(message, @sqlstate)
|
523
520
|
end
|
524
|
-
Packet.new(
|
521
|
+
Packet.new(data)
|
525
522
|
end
|
526
523
|
|
527
524
|
# Write one packet data
|
@@ -600,7 +597,7 @@ class Mysql
|
|
600
597
|
server_capabilities = pkt.ushort
|
601
598
|
server_charset = pkt.utiny
|
602
599
|
server_status = pkt.ushort
|
603
|
-
|
600
|
+
_f1 = pkt.read(13)
|
604
601
|
rest_scramble_buff = pkt.string
|
605
602
|
raise ProtocolError, "unsupported version: #{protocol_version}" unless protocol_version == VERSION
|
606
603
|
raise ProtocolError, "invalid packet: f0=#{f0}" unless f0 == 0
|
@@ -643,13 +640,13 @@ class Mysql
|
|
643
640
|
# Field packet
|
644
641
|
class FieldPacket
|
645
642
|
def self.parse(pkt)
|
646
|
-
|
643
|
+
_first = pkt.lcs
|
647
644
|
db = pkt.lcs
|
648
645
|
table = pkt.lcs
|
649
646
|
org_table = pkt.lcs
|
650
647
|
name = pkt.lcs
|
651
648
|
org_name = pkt.lcs
|
652
|
-
|
649
|
+
_f0 = pkt.utiny
|
653
650
|
charsetnr = pkt.ushort
|
654
651
|
length = pkt.ulong
|
655
652
|
type = pkt.utiny
|
data/lib/mysql.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# coding: ascii-8bit
|
2
|
-
# Copyright (C) 2008
|
2
|
+
# Copyright (C) 2008 TOMITA Masahiro
|
3
3
|
# mailto:tommy@tmtm.org
|
4
4
|
|
5
5
|
# MySQL connection class.
|
@@ -21,7 +21,7 @@ class Mysql
|
|
21
21
|
rescue LoadError
|
22
22
|
end
|
23
23
|
|
24
|
-
VERSION =
|
24
|
+
VERSION = 21000 # Version number of this library
|
25
25
|
MYSQL_UNIX_PORT = "/tmp/mysql.sock" # UNIX domain socket filename
|
26
26
|
MYSQL_TCP_PORT = 3306 # TCP socket port number
|
27
27
|
|
@@ -109,11 +109,11 @@ class Mysql
|
|
109
109
|
# @return self
|
110
110
|
def connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, socket=nil, flag=0)
|
111
111
|
if flag & CLIENT_COMPRESS != 0
|
112
|
-
warn 'unsupported flag: CLIENT_COMPRESS'
|
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
|
116
|
-
@protocol.authenticate user, passwd, db,
|
115
|
+
@protocol = Protocol.new host, port, socket, @connect_timeout, @read_timeout, @write_timeout, @local_infile
|
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"
|
119
119
|
query @init_command if @init_command
|
@@ -158,6 +158,8 @@ class Mysql
|
|
158
158
|
@connect_timeout = value
|
159
159
|
# when Mysql::GUESS_CONNECTION
|
160
160
|
when Mysql::OPT_LOCAL_INFILE
|
161
|
+
@local_infile = value ? '' : nil
|
162
|
+
when Mysql::OPT_LOAD_DATA_LOCAL_DIR
|
161
163
|
@local_infile = value
|
162
164
|
# when Mysql::OPT_NAMED_PIPE
|
163
165
|
# when Mysql::OPT_PROTOCOL
|
@@ -179,7 +181,7 @@ class Mysql
|
|
179
181
|
@charset = Charset.by_name value.to_s
|
180
182
|
# when Mysql::SHARED_MEMORY_BASE_NAME
|
181
183
|
else
|
182
|
-
warn "option not implemented: #{opt}"
|
184
|
+
warn "option not implemented: #{opt}" if $VERBOSE
|
183
185
|
end
|
184
186
|
self
|
185
187
|
end
|
@@ -731,8 +733,8 @@ class Mysql
|
|
731
733
|
max_length = Array.new(@fields.size, 0)
|
732
734
|
@records.each_with_index do |rec, i|
|
733
735
|
rec = @records[i] = rec.to_a if rec.is_a? RawRecord
|
734
|
-
max_length.each_index do |
|
735
|
-
max_length[
|
736
|
+
max_length.each_index do |j|
|
737
|
+
max_length[j] = rec[j].length if rec[j] && rec[j].length > max_length[j]
|
736
738
|
end
|
737
739
|
end
|
738
740
|
max_length.each_with_index do |len, i|
|