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