Class: Mysql::Protocol
Overview
MySQL network protocol
Defined Under Namespace
Classes: AuthenticationPacket, ExecutePacket, FieldPacket, InitialPacket, PrepareResultPacket, ResultPacket
Constant Summary collapse
- VERSION =
10
- MAX_PACKET_LENGTH =
2**24-1
Instance Attribute Summary collapse
-
#affected_rows ⇒ Object
readonly
Returns the value of attribute affected_rows.
-
#charset ⇒ Object
Returns the value of attribute charset.
-
#insert_id ⇒ Object
readonly
Returns the value of attribute insert_id.
-
#message ⇒ Object
readonly
Returns the value of attribute message.
-
#server_info ⇒ Object
readonly
Returns the value of attribute server_info.
-
#server_status ⇒ Object
readonly
Returns the value of attribute server_status.
-
#server_version ⇒ Object
readonly
Returns the value of attribute server_version.
-
#sqlstate ⇒ Object
readonly
Returns the value of attribute sqlstate.
-
#thread_id ⇒ Object
readonly
Returns the value of attribute thread_id.
-
#warning_count ⇒ Object
readonly
Returns the value of attribute warning_count.
Class Method Summary collapse
-
.net2value(pkt, type, unsigned) ⇒ Object
- Convert netdata to Ruby value === Argument data
- Packet
- packet data type
- Integer
- field type unsigned
- true or false
- true if value is unsigned === Return Object
-
converted value.
-
.value2net(v) ⇒ Object
- convert Ruby value to netdata === Argument v
- Object
-
Ruby value.
Instance Method Summary collapse
-
#authenticate(user, passwd, db, flag, charset) ⇒ Object
initial negotiate and authenticate.
- #close ⇒ Object
-
#field_list_command(table, field) ⇒ Object
- Field list command === Argument table
- String
-
table name.
- #gc_stmt(stmt_id) ⇒ Object
-
#get_result ⇒ Object
get result of query.
-
#initialize(host, port, socket, conn_timeout, read_timeout, write_timeout) ⇒ Protocol
constructor
make socket connection to server.
-
#kill_command(pid) ⇒ Object
Kill command.
-
#ping_command ⇒ Object
Ping command.
-
#process_info_command ⇒ Object
Process info command === Return [Array of Field] field list.
-
#query_command(query) ⇒ Object
- Query command === Argument query
- String
-
query string === Return [Integer / nil] number of fields of results.
-
#quit_command ⇒ Object
Quit command.
-
#refresh_command(op) ⇒ Object
Refresh command.
-
#retr_all_records(fields) ⇒ Object
- Retrieve all records for simple query === Argument fields
- Array<Mysql::Field>
-
number of fields === Return [Array of Array of String] all records.
-
#retr_fields(n) ⇒ Object
- Retrieve n fields === Argument n
- Integer
-
number of fields === Return [Array of Mysql::Field] field list.
-
#set_option_command(opt) ⇒ Object
Set option command.
-
#shutdown_command(level) ⇒ Object
Shutdown command.
-
#statistics_command ⇒ Object
Statistics command.
-
#stmt_close_command(stmt_id) ⇒ Object
- Stmt close command === Argument stmt_id
- Integer
-
statement id.
-
#stmt_execute_command(stmt_id, values) ⇒ Object
- Stmt execute command === Argument stmt_id
- Integer
- statement id values
- Array
-
parameters === Return [Integer] number of fields.
-
#stmt_prepare_command(stmt) ⇒ Object
- Stmt prepare command === Argument stmt
- String
-
prepared statement === Return [Integer] statement id [Integer] number of parameters [Array of Field] field list.
-
#stmt_retr_all_records(fields, charset) ⇒ Object
- Retrieve all records for prepared statement === Argument fields
- Array of Mysql::Fields
- field list charset
- Mysql::Charset
-
Return [Array of Array of Object] all records.
Constructor Details
#initialize(host, port, socket, conn_timeout, read_timeout, write_timeout) ⇒ Protocol
make socket connection to server.
Argument
- host
- String
-
if “localhost” or “” nil then use UNIXSocket. Otherwise use TCPSocket
- port
- Integer
-
port number using by TCPSocket
- socket
- String
-
socket file name using by UNIXSocket
- conn_timeout
- Integer
-
connect timeout (sec).
- read_timeout
- Integer
-
read timeout (sec).
- write_timeout
- Integer
-
write timeout (sec).
Exception
- ClientError
-
connection timeout
-
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/vendor/mysql/protocol.rb', line 139 def initialize(host, port, socket, conn_timeout, read_timeout, write_timeout) @insert_id = 0 @warning_count = 0 @gc_stmt_queue = [] # stmt id list which GC destroy. set_state :INIT @read_timeout = read_timeout @write_timeout = write_timeout begin Timeout.timeout conn_timeout do if host.nil? or host.empty? or host == "localhost" socket ||= ENV["MYSQL_UNIX_PORT"] || MYSQL_UNIX_PORT @sock = UNIXSocket.new socket else port ||= ENV["MYSQL_TCP_PORT"] || (Socket.getservbyname("mysql","tcp") rescue MYSQL_TCP_PORT) @sock = TCPSocket.new host, port end end rescue Timeout::Error raise ClientError, "connection timeout" end end |
Instance Attribute Details
#affected_rows ⇒ Object (readonly)
Returns the value of attribute affected_rows.
116 117 118 |
# File 'lib/vendor/mysql/protocol.rb', line 116 def affected_rows @affected_rows end |
#charset ⇒ Object
Returns the value of attribute charset.
121 122 123 |
# File 'lib/vendor/mysql/protocol.rb', line 121 def charset @charset end |
#insert_id ⇒ Object (readonly)
Returns the value of attribute insert_id.
117 118 119 |
# File 'lib/vendor/mysql/protocol.rb', line 117 def insert_id @insert_id end |
#message ⇒ Object (readonly)
Returns the value of attribute message.
120 121 122 |
# File 'lib/vendor/mysql/protocol.rb', line 120 def @message end |
#server_info ⇒ Object (readonly)
Returns the value of attribute server_info.
112 113 114 |
# File 'lib/vendor/mysql/protocol.rb', line 112 def server_info @server_info end |
#server_status ⇒ Object (readonly)
Returns the value of attribute server_status.
118 119 120 |
# File 'lib/vendor/mysql/protocol.rb', line 118 def server_status @server_status end |
#server_version ⇒ Object (readonly)
Returns the value of attribute server_version.
113 114 115 |
# File 'lib/vendor/mysql/protocol.rb', line 113 def server_version @server_version end |
#sqlstate ⇒ Object (readonly)
Returns the value of attribute sqlstate.
115 116 117 |
# File 'lib/vendor/mysql/protocol.rb', line 115 def sqlstate @sqlstate end |
#thread_id ⇒ Object (readonly)
Returns the value of attribute thread_id.
114 115 116 |
# File 'lib/vendor/mysql/protocol.rb', line 114 def thread_id @thread_id end |
#warning_count ⇒ Object (readonly)
Returns the value of attribute warning_count.
119 120 121 |
# File 'lib/vendor/mysql/protocol.rb', line 119 def warning_count @warning_count end |
Class Method Details
.net2value(pkt, type, unsigned) ⇒ Object
Convert netdata to Ruby value
Argument
- data
- Packet
-
packet data
- type
- Integer
-
field type
- unsigned
- true or false
-
true if value is unsigned
Return
- Object
-
converted value.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/vendor/mysql/protocol.rb', line 24 def self.net2value(pkt, type, unsigned) case type when Field::TYPE_STRING, Field::TYPE_VAR_STRING, Field::TYPE_NEWDECIMAL, Field::TYPE_BLOB return pkt.lcs when Field::TYPE_TINY v = pkt.utiny return unsigned ? v : v < 128 ? v : v-256 when Field::TYPE_SHORT v = pkt.ushort return unsigned ? v : v < 32768 ? v : v-65536 when Field::TYPE_INT24, Field::TYPE_LONG v = pkt.ulong return unsigned ? v : v < 0x8000_0000 ? v : v-0x10000_0000 when Field::TYPE_LONGLONG n1, n2 = pkt.ulong, pkt.ulong v = (n2 << 32) | n1 return unsigned ? v : v < 0x8000_0000_0000_0000 ? v : v-0x10000_0000_0000_0000 when Field::TYPE_FLOAT return pkt.read(4).unpack('e').first when Field::TYPE_DOUBLE return pkt.read(8).unpack('E').first when Field::TYPE_DATE len = pkt.utiny y, m, d = pkt.read(len).unpack("vCC") t = Mysql::Time.new(y, m, d, nil, nil, nil) return t when Field::TYPE_DATETIME, Field::TYPE_TIMESTAMP len = pkt.utiny y, m, d, h, mi, s, sp = pkt.read(len).unpack("vCCCCCV") return Mysql::Time.new(y, m, d, h, mi, s, false, sp) when Field::TYPE_TIME len = pkt.utiny sign, d, h, mi, s, sp = pkt.read(len).unpack("CVCCCV") h = d.to_i * 24 + h.to_i return Mysql::Time.new(0, 0, 0, h, mi, s, sign!=0, sp) when Field::TYPE_YEAR return pkt.ushort when Field::TYPE_BIT return pkt.lcs else raise "not implemented: type=#{type}" end end |
.value2net(v) ⇒ Object
convert Ruby value to netdata
Argument
- v
- Object
-
Ruby value.
Return
- Integer
-
type of column. Field::TYPE_*
- String
-
netdata
Exception
- ProtocolError
-
value too large / value is not supported
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/vendor/mysql/protocol.rb', line 76 def self.value2net(v) case v when nil type = Field::TYPE_NULL val = "" when Integer if -0x8000_0000 <= v && v < 0x8000_0000 type = Field::TYPE_LONG val = [v].pack('V') elsif -0x8000_0000_0000_0000 <= v && v < 0x8000_0000_0000_0000 type = Field::TYPE_LONGLONG val = [v&0xffffffff, v>>32].pack("VV") elsif 0x8000_0000_0000_0000 <= v && v <= 0xffff_ffff_ffff_ffff type = Field::TYPE_LONGLONG | 0x8000 val = [v&0xffffffff, v>>32].pack("VV") else raise ProtocolError, "value too large: #{v}" end when Float type = Field::TYPE_DOUBLE val = [v].pack("E") when String type = Field::TYPE_STRING val = Packet.lcs(v) when ::Time type = Field::TYPE_DATETIME val = [11, v.year, v.month, v.day, v.hour, v.min, v.sec, v.usec].pack("CvCCCCCV") when Mysql::Time type = Field::TYPE_DATETIME val = [11, v.year, v.month, v.day, v.hour, v.min, v.sec, v.second_part].pack("CvCCCCCV") else raise ProtocolError, "class #{v.class} is not supported" end return type, val end |
Instance Method Details
#authenticate(user, passwd, db, flag, charset) ⇒ Object
initial negotiate and authenticate.
Argument
- user
- String / nil
-
username
- passwd
- String / nil
-
password
- db
- String / nil
-
default database name. nil: no default.
- flag
- Integer
-
client flag
- charset
- Mysql::Charset / nil
-
charset for connection. nil: use server’s charset
Exception
- ProtocolError
-
The old style password is not supported
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/vendor/mysql/protocol.rb', line 174 def authenticate(user, passwd, db, flag, charset) check_state :INIT @authinfo = [user, passwd, db, flag, charset] reset init_packet = InitialPacket.parse read @server_info = init_packet.server_version @server_version = init_packet.server_version.split(/\D/)[0,3].inject{|a,b|a.to_i*100+b.to_i} @thread_id = init_packet.thread_id client_flags = CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_TRANSACTIONS | CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION client_flags |= CLIENT_CONNECT_WITH_DB if db client_flags |= flag @charset = charset unless @charset @charset = Charset.by_number(init_packet.server_charset) @charset.encoding # raise error if unsupported charset end netpw = encrypt_password passwd, init_packet.scramble_buff write AuthenticationPacket.serialize(client_flags, 1024**3, @charset.number, user, netpw, db) raise ProtocolError, 'The old style password is not supported' if read.to_s == "\xfe" set_state :READY end |
#close ⇒ Object
161 162 163 |
# File 'lib/vendor/mysql/protocol.rb', line 161 def close @sock.close end |
#field_list_command(table, field) ⇒ Object
Field list command
Argument
- table
- String
-
table name.
- field
- String / nil
-
field name that may contain wild card.
Return
- Array of Field
-
field list
293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/vendor/mysql/protocol.rb', line 293 def field_list_command(table, field) synchronize do reset write [COM_FIELD_LIST, table, 0, field].pack("Ca*Ca*") fields = [] until (data = read).eof? fields.push Field.new(FieldPacket.parse(data)) end return fields end end |
#gc_stmt(stmt_id) ⇒ Object
428 429 430 |
# File 'lib/vendor/mysql/protocol.rb', line 428 def gc_stmt(stmt_id) @gc_stmt_queue.push stmt_id end |
#get_result ⇒ Object
get result of query.
Return
- integer / nil
-
number of fields of results. nil if no results.
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/vendor/mysql/protocol.rb', line 225 def get_result begin res_packet = ResultPacket.parse read if res_packet.field_count.to_i > 0 # result data exists set_state :FIELD return res_packet.field_count end if res_packet.field_count.nil? # LOAD DATA LOCAL INFILE filename = res_packet. File.open(filename){|f| write f} write nil # EOF mark read end @affected_rows, @insert_id, @server_status, @warning_count, @message = res_packet.affected_rows, res_packet.insert_id, res_packet.server_status, res_packet.warning_count, res_packet. set_state :READY return nil rescue set_state :READY raise end end |
#kill_command(pid) ⇒ Object
Kill command
330 331 332 |
# File 'lib/vendor/mysql/protocol.rb', line 330 def kill_command(pid) simple_command [COM_PROCESS_KILL, pid].pack("CV") end |
#ping_command ⇒ Object
Ping command
325 326 327 |
# File 'lib/vendor/mysql/protocol.rb', line 325 def ping_command simple_command [COM_PING].pack("C") end |
#process_info_command ⇒ Object
Process info command
Return
- Array of Field
-
field list
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/vendor/mysql/protocol.rb', line 308 def process_info_command check_state :READY begin reset write [COM_PROCESS_INFO].pack("C") field_count = read.lcb fields = field_count.times.map{Field.new FieldPacket.parse(read)} read_eof_packet set_state :RESULT return fields rescue set_state :READY raise end end |
#query_command(query) ⇒ Object
Query command
Argument
- query
- String
-
query string
Return
- Integer / nil
-
number of fields of results. nil if no results.
210 211 212 213 214 215 216 217 218 219 220 |
# File 'lib/vendor/mysql/protocol.rb', line 210 def query_command(query) check_state :READY begin reset write [COM_QUERY, @charset.convert(query)].pack("Ca*") get_result rescue set_state :READY raise end end |
#quit_command ⇒ Object
Quit command
197 198 199 200 201 202 203 |
# File 'lib/vendor/mysql/protocol.rb', line 197 def quit_command synchronize do reset write [COM_QUIT].pack("C") close end end |
#refresh_command(op) ⇒ Object
Refresh command
335 336 337 |
# File 'lib/vendor/mysql/protocol.rb', line 335 def refresh_command(op) simple_command [COM_REFRESH, op].pack("CC") end |
#retr_all_records(fields) ⇒ Object
Retrieve all records for simple query
Argument
- fields
- Array<Mysql::Field>
-
number of fields
Return
- Array of Array of String
-
all records
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'lib/vendor/mysql/protocol.rb', line 271 def retr_all_records(fields) check_state :RESULT enc = charset.encoding begin all_recs = [] until (pkt = read).eof? all_recs.push RawRecord.new(pkt, fields, enc) end pkt.read(3) @server_status = pkt.utiny all_recs ensure set_state :READY end end |
#retr_fields(n) ⇒ Object
Retrieve n fields
Argument
- n
- Integer
-
number of fields
Return
- Array of Mysql::Field
-
field list
253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/vendor/mysql/protocol.rb', line 253 def retr_fields(n) check_state :FIELD begin fields = n.times.map{Field.new FieldPacket.parse(read)} read_eof_packet set_state :RESULT fields rescue set_state :READY raise end end |
#set_option_command(opt) ⇒ Object
Set option command
340 341 342 |
# File 'lib/vendor/mysql/protocol.rb', line 340 def set_option_command(opt) simple_command [COM_SET_OPTION, opt].pack("Cv") end |
#shutdown_command(level) ⇒ Object
Shutdown command
345 346 347 |
# File 'lib/vendor/mysql/protocol.rb', line 345 def shutdown_command(level) simple_command [COM_SHUTDOWN, level].pack("CC") end |
#statistics_command ⇒ Object
Statistics command
350 351 352 |
# File 'lib/vendor/mysql/protocol.rb', line 350 def statistics_command simple_command [COM_STATISTICS].pack("C") end |
#stmt_close_command(stmt_id) ⇒ Object
Stmt close command
Argument
- stmt_id
- Integer
-
statement id
421 422 423 424 425 426 |
# File 'lib/vendor/mysql/protocol.rb', line 421 def stmt_close_command(stmt_id) synchronize do reset write [COM_STMT_CLOSE, stmt_id].pack("CV") end end |
#stmt_execute_command(stmt_id, values) ⇒ Object
Stmt execute command
Argument
- stmt_id
- Integer
-
statement id
- values
- Array
-
parameters
Return
- Integer
-
number of fields
386 387 388 389 390 391 392 393 394 395 396 |
# File 'lib/vendor/mysql/protocol.rb', line 386 def stmt_execute_command(stmt_id, values) check_state :READY begin reset write ExecutePacket.serialize(stmt_id, Mysql::Stmt::CURSOR_TYPE_NO_CURSOR, values) get_result rescue set_state :READY raise end end |
#stmt_prepare_command(stmt) ⇒ Object
Stmt prepare command
Argument
- stmt
- String
-
prepared statement
Return
- Integer
-
statement id
- Integer
-
number of parameters
- Array of Field
-
field list
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'lib/vendor/mysql/protocol.rb', line 361 def stmt_prepare_command(stmt) synchronize do reset write [COM_STMT_PREPARE, charset.convert(stmt)].pack("Ca*") res_packet = PrepareResultPacket.parse read if res_packet.param_count > 0 res_packet.param_count.times{read} # skip parameter packet read_eof_packet end if res_packet.field_count > 0 fields = res_packet.field_count.times.map{Field.new FieldPacket.parse(read)} read_eof_packet else fields = [] end return res_packet.statement_id, res_packet.param_count, fields end end |
#stmt_retr_all_records(fields, charset) ⇒ Object
Retrieve all records for prepared statement
Argument
- fields
- Array of Mysql::Fields
-
field list
- charset
- Mysql::Charset
Return
- Array of Array of Object
-
all records
404 405 406 407 408 409 410 411 412 413 414 415 416 |
# File 'lib/vendor/mysql/protocol.rb', line 404 def stmt_retr_all_records(fields, charset) check_state :RESULT enc = charset.encoding begin all_recs = [] until (pkt = read).eof? all_recs.push StmtRawRecord.new(pkt, fields, enc) end all_recs ensure set_state :READY end end |