Closed nekpractice closed 11 years ago
@nekpractice can you provide more details against which version of MySQL you had issues connecting to?
There is no real_connect
method in this gem, at least not in Ruby (the code is in C)
Can you reproduce this with a bare/plain connection of mysql gem and MySQL server? can you provide those details?
Thank you.
I'm not much of a Ruby, C or GIT person. iirc, it was either or both MySQL 5.1 / 5.5 Supposedly this was fixed somewhere (MySQL 5.6?), but I don't remember just where / what version of what. I don't fully understand the question / request. So, here is the mysql.rb in full (without the patch - original version). (real_connect is the second method defined, right after the first one - initialize) (I don't know why some of the comments appear here as large and bold font, in particular the first 3 lines of a sharp, space, and then the comment text.):
# $Id: mysql.rb,v 1.24 2005/02/12 11:37:15 tommy Exp $
#
# Copyright (C) 2003-2005 TOMITA Masahiro
# tommy@tmtm.org
#
class Mysql
VERSION = "4.0-ruby-0.2.6-plus-changes"
require "socket"
require "digest/sha1"
MAX_PACKET_LENGTH = 256*256*256-1
MAX_ALLOWED_PACKET = 1024*1024*1024
MYSQL_UNIX_ADDR = "/tmp/mysql.sock"
MYSQL_PORT = 3306
PROTOCOL_VERSION = 10
SCRAMBLE_LENGTH = 20
SCRAMBLE_LENGTH_323 = 8
# Command
COM_SLEEP = 0
COM_QUIT = 1
COM_INIT_DB = 2
COM_QUERY = 3
COM_FIELD_LIST = 4
COM_CREATE_DB = 5
COM_DROP_DB = 6
COM_REFRESH = 7
COM_SHUTDOWN = 8
COM_STATISTICS = 9
COM_PROCESS_INFO = 10
COM_CONNECT = 11
COM_PROCESS_KILL = 12
COM_DEBUG = 13
COM_PING = 14
COM_TIME = 15
COM_DELAYED_INSERT = 16
COM_CHANGE_USER = 17
COM_BINLOG_DUMP = 18
COM_TABLE_DUMP = 19
COM_CONNECT_OUT = 20
COM_REGISTER_SLAVE = 21
# Client flag
CLIENT_LONG_PASSWORD = 1
CLIENT_FOUND_ROWS = 1 << 1
CLIENT_LONG_FLAG = 1 << 2
CLIENT_CONNECT_WITH_DB= 1 << 3
CLIENT_NO_SCHEMA = 1 << 4
CLIENT_COMPRESS = 1 << 5
CLIENT_ODBC = 1 << 6
CLIENT_LOCAL_FILES = 1 << 7
CLIENT_IGNORE_SPACE = 1 << 8
CLIENT_PROTOCOL_41 = 1 << 9
CLIENT_INTERACTIVE = 1 << 10
CLIENT_SSL = 1 << 11
CLIENT_IGNORE_SIGPIPE = 1 << 12
CLIENT_TRANSACTIONS = 1 << 13
CLIENT_RESERVED = 1 << 14
CLIENT_SECURE_CONNECTION = 1 << 15
CLIENT_CAPABILITIES = CLIENT_LONG_PASSWORD|CLIENT_LONG_FLAG|CLIENT_TRANSACTIONS
PROTO_AUTH41 = CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION
# Connection Option
OPT_CONNECT_TIMEOUT = 0
OPT_COMPRESS = 1
OPT_NAMED_PIPE = 2
INIT_COMMAND = 3
READ_DEFAULT_FILE = 4
READ_DEFAULT_GROUP = 5
SET_CHARSET_DIR = 6
SET_CHARSET_NAME = 7
OPT_LOCAL_INFILE = 8
# Server Status
SERVER_STATUS_IN_TRANS = 1
SERVER_STATUS_AUTOCOMMIT = 2
# Refresh parameter
REFRESH_GRANT = 1
REFRESH_LOG = 2
REFRESH_TABLES = 4
REFRESH_HOSTS = 8
REFRESH_STATUS = 16
REFRESH_THREADS = 32
REFRESH_SLAVE = 64
REFRESH_MASTER = 128
def initialize(*args)
@client_flag = 0
@max_allowed_packet = MAX_ALLOWED_PACKET
@query_with_result = true
@status = :STATUS_READY
if args[0] != :INIT then
real_connect(*args)
end
end
def real_connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, socket=nil, flag=nil)
@server_status = SERVER_STATUS_AUTOCOMMIT
if (host == nil or host == "localhost") and defined? UNIXSocket then
unix_socket = socket || ENV["MYSQL_UNIX_PORT"] || MYSQL_UNIX_ADDR
sock = UNIXSocket::new(unix_socket)
@host_info = Error::err(Error::CR_LOCALHOST_CONNECTION)
@unix_socket = unix_socket
else
sock = TCPSocket::new(host, port||ENV["MYSQL_TCP_PORT"]||(Socket::getservbyname("mysql","tcp") rescue MYSQL_PORT))
@host_info = sprintf Error::err(Error::CR_TCP_CONNECTION), host
end
@host = host ? host.dup : nil
sock.setsockopt Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true
@net = Net::new sock
a = read
@protocol_version = a.slice!(0)
@server_version, a = a.split(/\0/,2)
@thread_id, @scramble_buff = a.slice!(0,13).unpack("La8")
if a.size >= 2 then
@server_capabilities, = a.slice!(0,2).unpack("v")
end
if a.size >= 16 then
@server_language, @server_status = a.slice!(0,3).unpack("cv")
end
flag = 0 if flag == nil
flag |= @client_flag | CLIENT_CAPABILITIES
flag |= CLIENT_CONNECT_WITH_DB if db
@pre_411 = (0 == @server_capabilities & PROTO_AUTH41)
if @pre_411
data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+
(user||"")+"\0"+
scramble(passwd, @scramble_buff, @protocol_version==9)
else
dummy, @salt2 = a.unpack("a13a12")
@scramble_buff += @salt2
flag |= PROTO_AUTH41
data = Net::int4str(flag) + Net::int4str(@max_allowed_packet) +
([8] + Array.new(23, 0)).pack("c24") + (user||"")+"\0"+
scramble41(passwd, @scramble_buff)
end
if db and @server_capabilities & CLIENT_CONNECT_WITH_DB != 0
data << "\0" if @pre_411
data << db
@db = db.dup
end
write data
pkt = read
handle_auth_fallback(pkt, passwd)
ObjectSpace.define_finalizer(self, Mysql.finalizer(@net))
self
end
alias :connect :real_connect
def handle_auth_fallback(pkt, passwd)
# A packet like this means that we need to send an old-format password
if pkt.size == 1 and pkt[0] == 254 and
@server_capabilities & CLIENT_SECURE_CONNECTION != 0 then
data = scramble(passwd, @scramble_buff, @protocol_version == 9)
write data + "\0"
read
end
end
def escape_string(str)
Mysql::escape_string str
end
alias :quote :escape_string
def get_client_info()
VERSION
end
alias :client_info :get_client_info
def options(option, arg=nil)
if option == OPT_LOCAL_INFILE then
if arg == false or arg == 0 then
@client_flag &= ~CLIENT_LOCAL_FILES
else
@client_flag |= CLIENT_LOCAL_FILES
end
else
raise "not implemented"
end
end
def real_query(query)
command COM_QUERY, query, true
read_query_result
self
end
def use_result()
if @status != :STATUS_GET_RESULT then
error Error::CR_COMMANDS_OUT_OF_SYNC
end
res = Result::new self, @fields, @field_count
@status = :STATUS_USE_RESULT
res
end
def store_result()
if @status != :STATUS_GET_RESULT then
error Error::CR_COMMANDS_OUT_OF_SYNC
end
@status = :STATUS_READY
data = read_rows @field_count
res = Result::new self, @fields, @field_count, data
@fields = nil
@affected_rows = data.length
res
end
def change_user(user="", passwd="", db="")
if @pre_411
data = user+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)+"\0"+db
else
data = user+"\0"+scramble41(passwd, @scramble_buff)+db
end
pkt = command COM_CHANGE_USER, data
handle_auth_fallback(pkt, passwd)
@user = user
@passwd = passwd
@db = db
end
def character_set_name()
raise "not implemented"
end
def close()
@status = :STATUS_READY
command COM_QUIT, nil, true
@net.close
self
end
def create_db(db)
command COM_CREATE_DB, db
self
end
def drop_db(db)
command COM_DROP_DB, db
self
end
def dump_debug_info()
command COM_DEBUG
self
end
def get_host_info()
@host_info
end
alias :host_info :get_host_info
def get_proto_info()
@protocol_version
end
alias :proto_info :get_proto_info
def get_server_info()
@server_version
end
alias :server_info :get_server_info
def kill(id)
command COM_PROCESS_KILL, Net::int4str(id)
self
end
def list_dbs(db=nil)
real_query "show databases #{db}"
@status = :STATUS_READY
read_rows(1).flatten
end
def list_fields(table, field=nil)
command COM_FIELD_LIST, "#{table}\0#{field}", true
if @pre_411
f = read_rows 6
else
f = read_rows 7
end
fields = unpack_fields(f, @server_capabilities & CLIENT_LONG_FLAG != 0)
res = Result::new self, fields, f.length
res.eof = true
res
end
def list_processes()
data = command COM_PROCESS_INFO
@field_count = get_length data
if @pre_411
fields = read_rows 5
else
fields = read_rows 7
end
@fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0)
@status = :STATUS_GET_RESULT
store_result
end
def list_tables(table=nil)
real_query "show tables #{table}"
@status = :STATUS_READY
read_rows(1).flatten
end
def ping()
command COM_PING
self
end
def query(query)
real_query query
if not @query_with_result then
return self
end
if @field_count == 0 then
return nil
end
store_result
end
def refresh(r)
command COM_REFRESH, r.chr
self
end
def reload()
refresh REFRESH_GRANT
self
end
def select_db(db)
command COM_INIT_DB, db
@db = db
self
end
def shutdown()
command COM_SHUTDOWN
self
end
def stat()
command COM_STATISTICS
end
attr_reader :info, :insert_id, :affected_rows, :field_count, :thread_id
attr_accessor :query_with_result, :status
def read_one_row(field_count)
data = read
if data[0] == 254 and data.length == 1 ## EOF
return
elsif data[0] == 254 and data.length == 5
return
end
rec = []
field_count.times do
len = get_length data
if len == nil then
rec << len
else
rec << data.slice!(0,len)
end
end
rec
end
def skip_result()
if @status == :STATUS_USE_RESULT then
loop do
data = read
break if data[0] == 254 and data.length == 1
end
@status = :STATUS_READY
end
end
def inspect()
"#<#{self.class}>"
end
private
def read_query_result()
data = read
@field_count = get_length(data)
if @field_count == nil then # LOAD DATA LOCAL INFILE
File::open(data) do |f|
write f.read
end
write "" # mark EOF
data = read
@field_count = get_length(data)
end
if @field_count == 0 then
@affected_rows = get_length(data, true)
@insert_id = get_length(data, true)
if @server_capabilities & CLIENT_TRANSACTIONS != 0 then
a = data.slice!(0,2)
@server_status = a[0]+a[1]*256
end
if data.size > 0 and get_length(data) then
@info = data
end
else
@extra_info = get_length(data, true)
if @pre_411
fields = read_rows(5)
else
fields = read_rows(7)
end
@fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0)
@status = :STATUS_GET_RESULT
end
self
end
def unpack_fields(data, long_flag_protocol)
ret = []
data.each do |f|
if @pre_411
table = org_table = f[0]
name = f[1]
length = f[2][0]+f[2][1]*256+f[2][2]*256*256
type = f[3][0]
if long_flag_protocol then
flags = f[4][0]+f[4][1]*256
decimals = f[4][2]
else
flags = f[4][0]
decimals = f[4][1]
end
def_value = f[5]
max_length = 0
else
catalog = f[0]
db = f[1]
table = f[2]
org_table = f[3]
name = f[4]
org_name = f[5]
length = f[6][2]+f[6][3]*256+f[6][4]*256*256
type = f[6][6]
flags = f[6][7]+f[6][8]*256
decimals = f[6][9]
def_value = ""
max_length = 0
end
ret << Field::new(table, org_table, name, length, type, flags, decimals, def_value, max_length)
end
ret
end
def read_rows(field_count)
ret = []
while rec = read_one_row(field_count) do
ret << rec
end
ret
end
def get_length(data, longlong=nil)
return if data.length == 0
c = data.slice!(0)
case c
when 251
return nil
when 252
a = data.slice!(0,2)
return a[0]+a[1]*256
when 253
a = data.slice!(0,3)
return a[0]+a[1]*256+a[2]*256**2
when 254
a = data.slice!(0,8)
if longlong then
return a[0]+a[1]*256+a[2]*256**2+a[3]*256**3+
a[4]*256**4+a[5]*256**5+a[6]*256**6+a[7]*256**7
else
return a[0]+a[1]*256+a[2]*256**2+a[3]*256**3
end
else
c
end
end
def command(cmd, arg=nil, skip_check=nil)
unless @net then
error Error::CR_SERVER_GONE_ERROR
end
if @status != :STATUS_READY then
error Error::CR_COMMANDS_OUT_OF_SYNC
end
@net.clear
write cmd.chr+(arg||"")
read unless skip_check
end
def read()
unless @net then
error Error::CR_SERVER_GONE_ERROR
end
a = @net.read
if a[0] == 255 then
if a.length > 3 then
@errno = a[1]+a[2]*256
@error = a[3 .. -1]
else
@errno = Error::CR_UNKNOWN_ERROR
@error = Error::err @errno
end
raise Error::new(@errno, @error)
end
a
end
def write(arg)
unless @net then
error Error::CR_SERVER_GONE_ERROR
end
@net.write arg
end
def hash_password(password)
nr = 1345345333
add = 7
nr2 = 0x12345671
password.each_byte do |i|
next if i == 0x20 or i == 9
nr ^= (((nr & 63) + add) * i) + (nr << 8)
nr2 += (nr2 << 8) ^ nr
add += i
end
[nr & ((1 << 31) - 1), nr2 & ((1 << 31) - 1)]
end
def scramble(password, message, old_ver)
return "" if password == nil or password == ""
raise "old version password is not implemented" if old_ver
hash_pass = hash_password password
hash_message = hash_password message.slice(0,SCRAMBLE_LENGTH_323)
rnd = Random::new hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1]
to = []
1.upto(SCRAMBLE_LENGTH_323) do
to << ((rnd.rnd*31)+64).floor
end
extra = (rnd.rnd*31).floor
to.map! do |t| (t ^ extra).chr end
to.join
end
def scramble41(password, message)
return 0x00.chr if password.nil? or password.empty?
buf = [0x14]
s1 = Digest::SHA1.digest(password)
s2 = Digest::SHA1.digest(s1)
x = Digest::SHA1.digest(message + s2)
(0..s1.length - 1).each {|i| buf.push(s1[i] ^ x[i])}
buf.pack("C*")
end
def error(errno)
@errno = errno
@error = Error::err errno
raise Error::new(@errno, @error)
end
class Result
def initialize(mysql, fields, field_count, data=nil)
@handle = mysql
@fields = fields
@field_count = field_count
@data = data
@current_field = 0
@current_row = 0
@eof = false
@row_count = 0
end
attr_accessor :eof
def data_seek(n)
@current_row = n
end
def fetch_field()
return if @current_field >= @field_count
f = @fields[@current_field]
@current_field += 1
f
end
def fetch_fields()
@fields
end
def fetch_field_direct(n)
@fields[n]
end
def fetch_lengths()
@data ? @data[@current_row].map{|i| i ? i.length : 0} : @lengths
end
def fetch_row()
if @data then
if @current_row >= @data.length then
@handle.status = :STATUS_READY
return
end
ret = @data[@current_row]
@current_row += 1
else
return if @eof
ret = @handle.read_one_row @field_count
if ret == nil then
@eof = true
return
end
@lengths = ret.map{|i| i ? i.length : 0}
@row_count += 1
end
ret
end
def fetch_hash(with_table=nil)
row = fetch_row
return if row == nil
hash = {}
@fields.each_index do |i|
f = with_table ? @fields[i].table+"."+@fields[i].name : @fields[i].name
hash[f] = row[i]
end
hash
end
def field_seek(n)
@current_field = n
end
def field_tell()
@current_field
end
def free()
@handle.skip_result
@handle = @fields = @data = nil
end
def num_fields()
@field_count
end
def num_rows()
@data ? @data.length : @row_count
end
def row_seek(n)
@current_row = n
end
def row_tell()
@current_row
end
def each()
while row = fetch_row do
yield row
end
end
def each_hash(with_table=nil)
while hash = fetch_hash(with_table) do
yield hash
end
end
def inspect()
"#<#{self.class}>"
end
end
class Field
# Field type
TYPE_DECIMAL = 0
TYPE_TINY = 1
TYPE_SHORT = 2
TYPE_LONG = 3
TYPE_FLOAT = 4
TYPE_DOUBLE = 5
TYPE_NULL = 6
TYPE_TIMESTAMP = 7
TYPE_LONGLONG = 8
TYPE_INT24 = 9
TYPE_DATE = 10
TYPE_TIME = 11
TYPE_DATETIME = 12
TYPE_YEAR = 13
TYPE_NEWDATE = 14
TYPE_ENUM = 247
TYPE_SET = 248
TYPE_TINY_BLOB = 249
TYPE_MEDIUM_BLOB = 250
TYPE_LONG_BLOB = 251
TYPE_BLOB = 252
TYPE_VAR_STRING = 253
TYPE_STRING = 254
TYPE_GEOMETRY = 255
TYPE_CHAR = TYPE_TINY
TYPE_INTERVAL = TYPE_ENUM
# Flag
NOT_NULL_FLAG = 1
PRI_KEY_FLAG = 2
UNIQUE_KEY_FLAG = 4
MULTIPLE_KEY_FLAG = 8
BLOB_FLAG = 16
UNSIGNED_FLAG = 32
ZEROFILL_FLAG = 64
BINARY_FLAG = 128
ENUM_FLAG = 256
AUTO_INCREMENT_FLAG = 512
TIMESTAMP_FLAG = 1024
SET_FLAG = 2048
NUM_FLAG = 32768
PART_KEY_FLAG = 16384
GROUP_FLAG = 32768
UNIQUE_FLAG = 65536
def initialize(table, org_table, name, length, type, flags, decimals, def_value, max_length)
@table = table
@org_table = org_table
@name = name
@length = length
@type = type
@flags = flags
@decimals = decimals
@def = def_value
@max_length = max_length
if (type <= TYPE_INT24 and (type != TYPE_TIMESTAMP or length == 14 or length == 8)) or type == TYPE_YEAR then
@flags |= NUM_FLAG
end
end
attr_reader :table, :org_table, :name, :length, :type, :flags, :decimals, :def, :max_length
def inspect()
"#<#{self.class}:#{@name}>"
end
end
class Error < StandardError
# Server Error
ER_HASHCHK = 1000
ER_NISAMCHK = 1001
ER_NO = 1002
ER_YES = 1003
ER_CANT_CREATE_FILE = 1004
ER_CANT_CREATE_TABLE = 1005
ER_CANT_CREATE_DB = 1006
ER_DB_CREATE_EXISTS = 1007
ER_DB_DROP_EXISTS = 1008
ER_DB_DROP_DELETE = 1009
ER_DB_DROP_RMDIR = 1010
ER_CANT_DELETE_FILE = 1011
ER_CANT_FIND_SYSTEM_REC = 1012
ER_CANT_GET_STAT = 1013
ER_CANT_GET_WD = 1014
ER_CANT_LOCK = 1015
ER_CANT_OPEN_FILE = 1016
ER_FILE_NOT_FOUND = 1017
ER_CANT_READ_DIR = 1018
ER_CANT_SET_WD = 1019
ER_CHECKREAD = 1020
ER_DISK_FULL = 1021
ER_DUP_KEY = 1022
ER_ERROR_ON_CLOSE = 1023
ER_ERROR_ON_READ = 1024
ER_ERROR_ON_RENAME = 1025
ER_ERROR_ON_WRITE = 1026
ER_FILE_USED = 1027
ER_FILSORT_ABORT = 1028
ER_FORM_NOT_FOUND = 1029
ER_GET_ERRNO = 1030
ER_ILLEGAL_HA = 1031
ER_KEY_NOT_FOUND = 1032
ER_NOT_FORM_FILE = 1033
ER_NOT_KEYFILE = 1034
ER_OLD_KEYFILE = 1035
ER_OPEN_AS_READONLY = 1036
ER_OUTOFMEMORY = 1037
ER_OUT_OF_SORTMEMORY = 1038
ER_UNEXPECTED_EOF = 1039
ER_CON_COUNT_ERROR = 1040
ER_OUT_OF_RESOURCES = 1041
ER_BAD_HOST_ERROR = 1042
ER_HANDSHAKE_ERROR = 1043
ER_DBACCESS_DENIED_ERROR = 1044
ER_ACCESS_DENIED_ERROR = 1045
ER_NO_DB_ERROR = 1046
ER_UNKNOWN_COM_ERROR = 1047
ER_BAD_NULL_ERROR = 1048
ER_BAD_DB_ERROR = 1049
ER_TABLE_EXISTS_ERROR = 1050
ER_BAD_TABLE_ERROR = 1051
ER_NON_UNIQ_ERROR = 1052
ER_SERVER_SHUTDOWN = 1053
ER_BAD_FIELD_ERROR = 1054
ER_WRONG_FIELD_WITH_GROUP = 1055
ER_WRONG_GROUP_FIELD = 1056
ER_WRONG_SUM_SELECT = 1057
ER_WRONG_VALUE_COUNT = 1058
ER_TOO_LONG_IDENT = 1059
ER_DUP_FIELDNAME = 1060
ER_DUP_KEYNAME = 1061
ER_DUP_ENTRY = 1062
ER_WRONG_FIELD_SPEC = 1063
ER_PARSE_ERROR = 1064
ER_EMPTY_QUERY = 1065
ER_NONUNIQ_TABLE = 1066
ER_INVALID_DEFAULT = 1067
ER_MULTIPLE_PRI_KEY = 1068
ER_TOO_MANY_KEYS = 1069
ER_TOO_MANY_KEY_PARTS = 1070
ER_TOO_LONG_KEY = 1071
ER_KEY_COLUMN_DOES_NOT_EXITS = 1072
ER_BLOB_USED_AS_KEY = 1073
ER_TOO_BIG_FIELDLENGTH = 1074
ER_WRONG_AUTO_KEY = 1075
ER_READY = 1076
ER_NORMAL_SHUTDOWN = 1077
ER_GOT_SIGNAL = 1078
ER_SHUTDOWN_COMPLETE = 1079
ER_FORCING_CLOSE = 1080
ER_IPSOCK_ERROR = 1081
ER_NO_SUCH_INDEX = 1082
ER_WRONG_FIELD_TERMINATORS = 1083
ER_BLOBS_AND_NO_TERMINATED = 1084
ER_TEXTFILE_NOT_READABLE = 1085
ER_FILE_EXISTS_ERROR = 1086
ER_LOAD_INFO = 1087
ER_ALTER_INFO = 1088
ER_WRONG_SUB_KEY = 1089
ER_CANT_REMOVE_ALL_FIELDS = 1090
ER_CANT_DROP_FIELD_OR_KEY = 1091
ER_INSERT_INFO = 1092
ER_INSERT_TABLE_USED = 1093
ER_NO_SUCH_THREAD = 1094
ER_KILL_DENIED_ERROR = 1095
ER_NO_TABLES_USED = 1096
ER_TOO_BIG_SET = 1097
ER_NO_UNIQUE_LOGFILE = 1098
ER_TABLE_NOT_LOCKED_FOR_WRITE = 1099
ER_TABLE_NOT_LOCKED = 1100
ER_BLOB_CANT_HAVE_DEFAULT = 1101
ER_WRONG_DB_NAME = 1102
ER_WRONG_TABLE_NAME = 1103
ER_TOO_BIG_SELECT = 1104
ER_UNKNOWN_ERROR = 1105
ER_UNKNOWN_PROCEDURE = 1106
ER_WRONG_PARAMCOUNT_TO_PROCEDURE = 1107
ER_WRONG_PARAMETERS_TO_PROCEDURE = 1108
ER_UNKNOWN_TABLE = 1109
ER_FIELD_SPECIFIED_TWICE = 1110
ER_INVALID_GROUP_FUNC_USE = 1111
ER_UNSUPPORTED_EXTENSION = 1112
ER_TABLE_MUST_HAVE_COLUMNS = 1113
ER_RECORD_FILE_FULL = 1114
ER_UNKNOWN_CHARACTER_SET = 1115
ER_TOO_MANY_TABLES = 1116
ER_TOO_MANY_FIELDS = 1117
ER_TOO_BIG_ROWSIZE = 1118
ER_STACK_OVERRUN = 1119
ER_WRONG_OUTER_JOIN = 1120
ER_NULL_COLUMN_IN_INDEX = 1121
ER_CANT_FIND_UDF = 1122
ER_CANT_INITIALIZE_UDF = 1123
ER_UDF_NO_PATHS = 1124
ER_UDF_EXISTS = 1125
ER_CANT_OPEN_LIBRARY = 1126
ER_CANT_FIND_DL_ENTRY = 1127
ER_FUNCTION_NOT_DEFINED = 1128
ER_HOST_IS_BLOCKED = 1129
ER_HOST_NOT_PRIVILEGED = 1130
ER_PASSWORD_ANONYMOUS_USER = 1131
ER_PASSWORD_NOT_ALLOWED = 1132
ER_PASSWORD_NO_MATCH = 1133
ER_UPDATE_INFO = 1134
ER_CANT_CREATE_THREAD = 1135
ER_WRONG_VALUE_COUNT_ON_ROW = 1136
ER_CANT_REOPEN_TABLE = 1137
ER_INVALID_USE_OF_NULL = 1138
ER_REGEXP_ERROR = 1139
ER_MIX_OF_GROUP_FUNC_AND_FIELDS = 1140
ER_NONEXISTING_GRANT = 1141
ER_TABLEACCESS_DENIED_ERROR = 1142
ER_COLUMNACCESS_DENIED_ERROR = 1143
ER_ILLEGAL_GRANT_FOR_TABLE = 1144
ER_GRANT_WRONG_HOST_OR_USER = 1145
ER_NO_SUCH_TABLE = 1146
ER_NONEXISTING_TABLE_GRANT = 1147
ER_NOT_ALLOWED_COMMAND = 1148
ER_SYNTAX_ERROR = 1149
ER_DELAYED_CANT_CHANGE_LOCK = 1150
ER_TOO_MANY_DELAYED_THREADS = 1151
ER_ABORTING_CONNECTION = 1152
ER_NET_PACKET_TOO_LARGE = 1153
ER_NET_READ_ERROR_FROM_PIPE = 1154
ER_NET_FCNTL_ERROR = 1155
ER_NET_PACKETS_OUT_OF_ORDER = 1156
ER_NET_UNCOMPRESS_ERROR = 1157
ER_NET_READ_ERROR = 1158
ER_NET_READ_INTERRUPTED = 1159
ER_NET_ERROR_ON_WRITE = 1160
ER_NET_WRITE_INTERRUPTED = 1161
ER_TOO_LONG_STRING = 1162
ER_TABLE_CANT_HANDLE_BLOB = 1163
ER_TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164
ER_DELAYED_INSERT_TABLE_LOCKED = 1165
ER_WRONG_COLUMN_NAME = 1166
ER_WRONG_KEY_COLUMN = 1167
ER_WRONG_MRG_TABLE = 1168
ER_DUP_UNIQUE = 1169
ER_BLOB_KEY_WITHOUT_LENGTH = 1170
ER_PRIMARY_CANT_HAVE_NULL = 1171
ER_TOO_MANY_ROWS = 1172
ER_REQUIRES_PRIMARY_KEY = 1173
ER_NO_RAID_COMPILED = 1174
ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175
ER_KEY_DOES_NOT_EXITS = 1176
ER_CHECK_NO_SUCH_TABLE = 1177
ER_CHECK_NOT_IMPLEMENTED = 1178
ER_CANT_DO_THIS_DURING_AN_TRANSACTION = 1179
ER_ERROR_DURING_COMMIT = 1180
ER_ERROR_DURING_ROLLBACK = 1181
ER_ERROR_DURING_FLUSH_LOGS = 1182
ER_ERROR_DURING_CHECKPOINT = 1183
ER_NEW_ABORTING_CONNECTION = 1184
ER_DUMP_NOT_IMPLEMENTED = 1185
ER_FLUSH_MASTER_BINLOG_CLOSED = 1186
ER_INDEX_REBUILD = 1187
ER_MASTER = 1188
ER_MASTER_NET_READ = 1189
ER_MASTER_NET_WRITE = 1190
ER_FT_MATCHING_KEY_NOT_FOUND = 1191
ER_LOCK_OR_ACTIVE_TRANSACTION = 1192
ER_UNKNOWN_SYSTEM_VARIABLE = 1193
ER_CRASHED_ON_USAGE = 1194
ER_CRASHED_ON_REPAIR = 1195
ER_WARNING_NOT_COMPLETE_ROLLBACK = 1196
ER_TRANS_CACHE_FULL = 1197
ER_SLAVE_MUST_STOP = 1198
ER_SLAVE_NOT_RUNNING = 1199
ER_BAD_SLAVE = 1200
ER_MASTER_INFO = 1201
ER_SLAVE_THREAD = 1202
ER_TOO_MANY_USER_CONNECTIONS = 1203
ER_SET_CONSTANTS_ONLY = 1204
ER_LOCK_WAIT_TIMEOUT = 1205
ER_LOCK_TABLE_FULL = 1206
ER_READ_ONLY_TRANSACTION = 1207
ER_DROP_DB_WITH_READ_LOCK = 1208
ER_CREATE_DB_WITH_READ_LOCK = 1209
ER_WRONG_ARGUMENTS = 1210
ER_NO_PERMISSION_TO_CREATE_USER = 1211
ER_UNION_TABLES_IN_DIFFERENT_DIR = 1212
ER_LOCK_DEADLOCK = 1213
ER_TABLE_CANT_HANDLE_FULLTEXT = 1214
ER_CANNOT_ADD_FOREIGN = 1215
ER_NO_REFERENCED_ROW = 1216
ER_ROW_IS_REFERENCED = 1217
ER_CONNECT_TO_MASTER = 1218
ER_QUERY_ON_MASTER = 1219
ER_ERROR_WHEN_EXECUTING_COMMAND = 1220
ER_WRONG_USAGE = 1221
ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222
ER_CANT_UPDATE_WITH_READLOCK = 1223
ER_MIXING_NOT_ALLOWED = 1224
ER_DUP_ARGUMENT = 1225
ER_USER_LIMIT_REACHED = 1226
ER_SPECIFIC_ACCESS_DENIED_ERROR = 1227
ER_LOCAL_VARIABLE = 1228
ER_GLOBAL_VARIABLE = 1229
ER_NO_DEFAULT = 1230
ER_WRONG_VALUE_FOR_VAR = 1231
ER_WRONG_TYPE_FOR_VAR = 1232
ER_VAR_CANT_BE_READ = 1233
ER_CANT_USE_OPTION_HERE = 1234
ER_NOT_SUPPORTED_YET = 1235
ER_MASTER_FATAL_ERROR_READING_BINLOG = 1236
ER_SLAVE_IGNORED_TABLE = 1237
ER_ERROR_MESSAGES = 238
# Client Error
CR_MIN_ERROR = 2000
CR_MAX_ERROR = 2999
CR_UNKNOWN_ERROR = 2000
CR_SOCKET_CREATE_ERROR = 2001
CR_CONNECTION_ERROR = 2002
CR_CONN_HOST_ERROR = 2003
CR_IPSOCK_ERROR = 2004
CR_UNKNOWN_HOST = 2005
CR_SERVER_GONE_ERROR = 2006
CR_VERSION_ERROR = 2007
CR_OUT_OF_MEMORY = 2008
CR_WRONG_HOST_INFO = 2009
CR_LOCALHOST_CONNECTION = 2010
CR_TCP_CONNECTION = 2011
CR_SERVER_HANDSHAKE_ERR = 2012
CR_SERVER_LOST = 2013
CR_COMMANDS_OUT_OF_SYNC = 2014
CR_NAMEDPIPE_CONNECTION = 2015
CR_NAMEDPIPEWAIT_ERROR = 2016
CR_NAMEDPIPEOPEN_ERROR = 2017
CR_NAMEDPIPESETSTATE_ERROR = 2018
CR_CANT_READ_CHARSET = 2019
CR_NET_PACKET_TOO_LARGE = 2020
CR_EMBEDDED_CONNECTION = 2021
CR_PROBE_SLAVE_STATUS = 2022
CR_PROBE_SLAVE_HOSTS = 2023
CR_PROBE_SLAVE_CONNECT = 2024
CR_PROBE_MASTER_CONNECT = 2025
CR_SSL_CONNECTION_ERROR = 2026
CR_MALFORMED_PACKET = 2027
CLIENT_ERRORS = [
"Unknown MySQL error",
"Can't create UNIX socket (%d)",
"Can't connect to local MySQL server through socket '%-.64s' (%d)",
"Can't connect to MySQL server on '%-.64s' (%d)",
"Can't create TCP/IP socket (%d)",
"Unknown MySQL Server Host '%-.64s' (%d)",
"MySQL server has gone away",
"Protocol mismatch. Server Version = %d Client Version = %d",
"MySQL client run out of memory",
"Wrong host info",
"Localhost via UNIX socket",
"%-.64s via TCP/IP",
"Error in server handshake",
"Lost connection to MySQL server during query",
"Commands out of sync; You can't run this command now",
"%-.64s via named pipe",
"Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)",
"Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)",
"Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)",
"Can't initialize character set %-.64s (path: %-.64s)",
"Got packet bigger than 'max_allowed_packet'",
"Embedded server",
"Error on SHOW SLAVE STATUS:",
"Error on SHOW SLAVE HOSTS:",
"Error connecting to slave:",
"Error connecting to master:",
"SSL connection error",
"Malformed packet"
]
def initialize(errno, error)
@errno = errno
@error = error
super error
end
attr_reader :errno, :error
def Error::err(errno)
CLIENT_ERRORS[errno - Error::CR_MIN_ERROR]
end
end
class Net
def initialize(sock)
@sock = sock
@pkt_nr = 0
end
def clear()
@pkt_nr = 0
end
def read()
buf = []
len = nil
@sock.sync = false
while len == nil or len == MAX_PACKET_LENGTH do
a = @sock.read(4)
len = a[0]+a[1]*256+a[2]*256*256
pkt_nr = a[3]
if @pkt_nr != pkt_nr then
raise "Packets out of order: #{@pkt_nr}<>#{pkt_nr}"
end
@pkt_nr = @pkt_nr + 1 & 0xff
buf << @sock.read(len)
end
@sock.sync = true
buf.join
rescue
errno = Error::CR_SERVER_LOST
raise Error::new(errno, Error::err(errno))
end
def write(data)
if data.is_a? Array then
data = data.join
end
@sock.sync = false
ptr = 0
while data.length >= MAX_PACKET_LENGTH do
@sock.write Net::int3str(MAX_PACKET_LENGTH)+@pkt_nr.chr+data[ptr, MAX_PACKET_LENGTH]
@pkt_nr = @pkt_nr + 1 & 0xff
ptr += MAX_PACKET_LENGTH
end
@sock.write Net::int3str(data.length-ptr)+@pkt_nr.chr+data[ptr .. -1]
@pkt_nr = @pkt_nr + 1 & 0xff
@sock.sync = true
@sock.flush
rescue
errno = Error::CR_SERVER_LOST
raise Error::new(errno, Error::err(errno))
end
def close()
@sock.close
end
def Net::int2str(n)
[n].pack("v")
end
def Net::int3str(n)
[n%256, n>>8].pack("cv")
end
def Net::int4str(n)
[n].pack("V")
end
end
class Random
def initialize(seed1, seed2)
@max_value = 0x3FFFFFFF
@seed1 = seed1 % @max_value
@seed2 = seed2 % @max_value
end
def rnd()
@seed1 = (@seed1*3+@seed2) % @max_value
@seed2 = (@seed1+@seed2+33) % @max_value
@seed1.to_f / @max_value
end
end
end
class << Mysql
def init()
Mysql::new :INIT
end
def real_connect(*args)
Mysql::new(*args)
end
alias :connect :real_connect
def finalizer(net)
proc {
net.clear
begin
net.write(Mysql::COM_QUIT.chr)
net.close
rescue # Ignore IOError if socket is already closed.
end
}
end
def escape_string(str)
str.gsub(/([\0\n\r\032\'\"\\])/) do
case $1
when "\0" then "\\0"
when "\n" then "\\n"
when "\r" then "\\r"
when "\032" then "\\Z"
else "\\"+$1
end
end
end
alias :quote :escape_string
def get_client_info()
Mysql::VERSION
end
alias :client_info :get_client_info
def debug(str)
raise "not implemented"
end
end
#
# for compatibility
#
MysqlRes = Mysql::Result
MysqlField = Mysql::Field
MysqlError = Mysql::Error
That looks like other gem, perhaps mysql-plus?
This project has no mysql.rb like that.
Sorry for top posting. Sent from mobile. On Feb 16, 2013 2:31 PM, "nekpractice" notifications@github.com wrote:
I'm not much of a Ruby or C person. iirc, it was either or both MySQL 5.1 / 5.5 Supposedly this was fixed somewhere, but I don't remember just where / what version of what. I don't fully understand the question / request. So, here is the mysql.rb in full (without the patch - original version). (real_connect is the second method defined, right after the first one - initialize) (I don't know why some of the comments appear here as large and bold font, in particular the first 3 lines of a sharp, space, and then the comment text.): $Id: mysql.rb,v 1.24 2005/02/12 11:37:15 tommy Exp $
# Copyright (C) 2003-2005 TOMITA Masahiro tommy@tmtm.org
#
class Mysql
VERSION = "4.0-ruby-0.2.6-plus-changes"
require "socket" require "digest/sha1"
MAX_PACKET_LENGTH = 256_256_256-1 MAX_ALLOWED_PACKET = 1024_1024_1024
MYSQL_UNIX_ADDR = "/tmp/mysql.sock" MYSQL_PORT = 3306 PROTOCOL_VERSION = 10
SCRAMBLE_LENGTH = 20 SCRAMBLE_LENGTH_323 = 8
Command
COM_SLEEP = 0 COM_QUIT = 1 COM_INIT_DB = 2 COM_QUERY = 3 COM_FIELD_LIST = 4 COM_CREATE_DB = 5 COM_DROP_DB = 6 COM_REFRESH = 7 COM_SHUTDOWN = 8 COM_STATISTICS = 9 COM_PROCESS_INFO = 10 COM_CONNECT = 11 COM_PROCESS_KILL = 12 COM_DEBUG = 13 COM_PING = 14 COM_TIME = 15 COM_DELAYED_INSERT = 16 COM_CHANGE_USER = 17 COM_BINLOG_DUMP = 18 COM_TABLE_DUMP = 19 COM_CONNECT_OUT = 20 COM_REGISTER_SLAVE = 21
Client flag
CLIENT_LONG_PASSWORD = 1 CLIENT_FOUND_ROWS = 1 << 1 CLIENT_LONG_FLAG = 1 << 2 CLIENT_CONNECT_WITH_DB= 1 << 3 CLIENT_NO_SCHEMA = 1 << 4 CLIENT_COMPRESS = 1 << 5 CLIENT_ODBC = 1 << 6 CLIENT_LOCAL_FILES = 1 << 7 CLIENT_IGNORE_SPACE = 1 << 8 CLIENT_PROTOCOL_41 = 1 << 9 CLIENT_INTERACTIVE = 1 << 10 CLIENT_SSL = 1 << 11 CLIENT_IGNORE_SIGPIPE = 1 << 12 CLIENT_TRANSACTIONS = 1 << 13 CLIENT_RESERVED = 1 << 14 CLIENT_SECURE_CONNECTION = 1 << 15 CLIENT_CAPABILITIES = CLIENT_LONG_PASSWORD|CLIENT_LONG_FLAG|CLIENT_TRANSACTIONS PROTO_AUTH41 = CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION
Connection Option
OPT_CONNECT_TIMEOUT = 0 OPT_COMPRESS = 1 OPT_NAMED_PIPE = 2 INIT_COMMAND = 3 READ_DEFAULT_FILE = 4 READ_DEFAULT_GROUP = 5 SET_CHARSET_DIR = 6 SET_CHARSET_NAME = 7 OPT_LOCAL_INFILE = 8
Server Status
SERVER_STATUS_IN_TRANS = 1 SERVER_STATUS_AUTOCOMMIT = 2
Refresh parameter
REFRESH_GRANT = 1 REFRESH_LOG = 2 REFRESH_TABLES = 4 REFRESH_HOSTS = 8 REFRESH_STATUS = 16 REFRESH_THREADS = 32 REFRESH_SLAVE = 64 REFRESH_MASTER = 128
def initialize(_args) @client_flag = 0 @max_allowed_packet = MAX_ALLOWED_PACKET @query_with_result = true @status = :STATUS_READY if args[0] != :INIT then real_connect(_args) end end
def real_connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, socket=nil, flag=nil) @server_status = SERVER_STATUS_AUTOCOMMIT if (host == nil or host == "localhost") and defined? UNIXSocket then unix_socket = socket || ENV["MYSQL_UNIX_PORT"] || MYSQL_UNIX_ADDR sock = UNIXSocket::new(unix_socket) @host_info = Error::err(Error::CR_LOCALHOST_CONNECTION) @unix_socket = unix_socket else
sock = TCPSocket::new(host, port||ENV["MYSQL_TCP_PORT"]||(Socket::getservbyname("mysql","tcp") rescue MYSQL_PORT)) @host_info = sprintf Error::err(Error::CR_TCP_CONNECTION), host end @host https://github.com/host = host ? host.dup : nil sock.setsockopt Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true @net https://github.com/net = Net::new sock
a = read @protocol_version = a.slice!(0) @server_version, a = a.split(/\0/,2) @thread_id, @scramble_buff = a.slice!(0,13).unpack("La8") if a.size >= 2 then @server_capabilities, = a.slice!(0,2).unpack("v") end if a.size >= 16 then @server_language, @server_status = a.slice!(0,3).unpack("cv") end
flag = 0 if flag == nil flag |= @client_flag | CLIENT_CAPABILITIES flag |= CLIENT_CONNECT_WITH_DB if db
@pre_411 = (0 == @server_capabilities & PROTO_AUTH41) if @pre_411 data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+ (user||"")+"\0"+ scramble(passwd, @scramble_buff, @protocol_version==9) else dummy, @salt2 = a.unpack("a13a12") @scramble_buff += @salt2 flag |= PROTO_AUTH41 data = Net::int4str(flag) + Net::int4str(@max_allowed_packet) + ([8] + Array.new(23, 0)).pack("c24") + (user||"")+"\0"+ scramble41(passwd, @scramble_buff) end
if db and @server_capabilities & CLIENT_CONNECT_WITH_DB != 0 data << "\0" if @pre_411 data << db @db = db.dup end write data pkt = read handle_auth_fallback(pkt, passwd) ObjectSpace.define_finalizer(self, Mysql.finalizer(@net)) self
end alias :connect :real_connect
def handle_auth_fallback(pkt, passwd)
A packet like this means that we need to send an old-format password
if pkt.size == 1 and pkt[0] == 254 and @server_capabilities & CLIENT_SECURE_CONNECTION != 0 then data = scramble(passwd, @scramble_buff, @protocol_version == 9) write data + "\0" read end end
def escape_string(str) Mysql::escape_string str end alias :quote :escape_string
def get_client_info() VERSION end alias :client_info :get_client_info
def options(option, arg=nil) if option == OPT_LOCAL_INFILE then if arg == false or arg == 0 then @client_flag &= ~CLIENT_LOCAL_FILES else @client_flag |= CLIENT_LOCAL_FILES end else raise "not implemented" end end
def real_query(query) command COM_QUERY, query, true read_query_result self end
def use_result() if @status != :STATUS_GET_RESULT then error Error::CR_COMMANDS_OUT_OF_SYNC end res = Result::new self, @fields https://github.com/fields, @field_count @status = :STATUS_USE_RESULT res end
def store_result() if @status != :STATUS_GET_RESULT then error Error::CR_COMMANDS_OUT_OF_SYNC end @status = :STATUS_READY data = read_rows @field_count res = Result::new self, @fields https://github.com/fields, @field_count, data @fields https://github.com/fields = nil @affected_rows = data.length res end
def change_user(user="", passwd="", db="") if @pre_411 data = user+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)+"\0"+db else data = user+"\0"+scramble41(passwd, @scramble_buff)+db end pkt = command COM_CHANGE_USER, data handle_auth_fallback(pkt, passwd) @user https://github.com/user = user @passwd https://github.com/passwd = passwd @db https://github.com/db = db end
def character_set_name() raise "not implemented" end
def close() @status = :STATUS_READY command COM_QUIT, nil, true @net.close self end
def create_db(db) command COM_CREATE_DB, db self end
def drop_db(db) command COM_DROP_DB, db self end
def dump_debug_info() command COM_DEBUG self end
def get_host_info() @host_info end alias :host_info :get_host_info
def get_proto_info() @protocol_version end alias :proto_info :get_proto_info
def get_server_info() @server_version end alias :server_info :get_server_info
def kill(id) command COM_PROCESS_KILL, Net::int4str(id) self end
def list_dbs(db=nil) real_query "show databases #{db}" @status = :STATUS_READY read_rows(1).flatten end
def list_fields(table, field=nil) command COM_FIELD_LIST, "#{table}\0#{field}", true if @pre_411 f = read_rows 6 else f = read_rows 7 end fields = unpack_fields(f, @server_capabilities & CLIENT_LONG_FLAG != 0) res = Result::new self, fields, f.length res.eof = true res end
def list_processes() data = command COM_PROCESS_INFO @field_count = get_length data if @pre_411 fields = read_rows 5 else fields = read_rows 7 end @fields https://github.com/fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0) @status = :STATUS_GET_RESULT store_result end
def list_tables(table=nil) real_query "show tables #{table}" @status = :STATUS_READY read_rows(1).flatten end
def ping() command COM_PING self end
def query(query) real_query query if not @query_with_result then return self end if @field_count == 0 then return nil end store_result end
def refresh(r) command COM_REFRESH, r.chr self end
def reload() refresh REFRESH_GRANT self end
def select_db(db) command COM_INIT_DB, db @db https://github.com/db = db self end
def shutdown() command COM_SHUTDOWN self end
def stat() command COM_STATISTICS end
attr_reader :info, :insert_id, :affected_rows, :field_count, :thread_id attr_accessor :query_with_result, :status
def read_one_row(field_count) data = read if data[0] == 254 and data.length == 1 ## EOF return elsif data[0] == 254 and data.length == 5 return end rec = [] field_count.times do len = get_length data if len == nil then rec << len else rec << data.slice!(0,len) end end rec end
def skip_result() if @status == :STATUS_USE_RESULT then loop do data = read break if data[0] == 254 and data.length == 1 end @status = :STATUS_READY end end
def inspect() "#<#{self.class}>" end
private
def read_query_result() data = read @field_count = get_length(data) if @field_count == nil then # LOAD DATA LOCAL INFILE File::open(data) do |f| write f.read end write "" # mark EOF data = read @field_count = get_length(data) end if @field_count == 0 then @affected_rows = get_length(data, true) @insert_id = get_length(data, true) if @server_capabilities & CLIENT_TRANSACTIONS != 0 then a = data.slice!(0,2) @server_status = a[0]+a[1]*256 end if data.size > 0 and get_length(data) then @info = data end else @extra_info = get_length(data, true) if @pre_411 fields = read_rows(5) else fields = read_rows(7) end @fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0) @status = :STATUS_GET_RESULT end self end
def unpack_fields(data, long_flag_protocol) ret = [] data.each do |f| if @pre_411 table = org_table = f[0] name = f[1] length = f[2][0]+f[2][1]_256+f[2][2]_256_256 type = f[3][0] if long_flag_protocol then flags = f[4][0]+f[4][1]_256 decimals = f[4][2] else flags = f[4][0] decimals = f[4][1] end def_value = f[5] max_length = 0 else catalog = f[0] db = f[1] table = f[2] org_table = f[3] name = f[4] org_name = f[5] length = f[6][2]+f[6][3]_256+f[6][4]_256_256 type = f[6][6] flags = f[6][7]+f[6][8]_256 decimals = f[6][9] def_value = "" max_length = 0 end ret << Field::new(table, org_table, name, length, type, flags, decimals, def_value, max_length) end ret end
def read_rows(field_count) ret = [] while rec = read_one_row(field_count) do ret << rec end ret end
def get_length(data, longlong=nil) return if data.length == 0 c = data.slice!(0) case c when 251 return nil when 252 a = data.slice!(0,2) return a[0]+a[1]_256 when 253 a = data.slice!(0,3) return a[0]+a[1]_256+a[2]_2562 when 254 a = data.slice!(0,8) if longlong then return a[0]+a[1]_256+a[2]_2562+a[3]_2563+ a[4]2564+a[5]_256__5+a[6]_2566+a[7]2567 else return a[0]+a[1]_256+a[2]_256*2+a[3]256**3 end else c end end
def command(cmd, arg=nil, skip_check=nil) unless @net then error Error::CR_SERVER_GONE_ERROR end if @status != :STATUS_READY then error Error::CR_COMMANDS_OUT_OF_SYNC end @net.clear write cmd.chr+(arg||"") read unless skip_check end
def read() unless @net then error Error::CR_SERVER_GONE_ERROR end a = @net.read if a[0] == 255 then if a.length > 3 then @errno = a[1]+a[2]*256 @error = a[3 .. -1] else @errno = Error::CR_UNKNOWN_ERROR @error = Error::err @errno end raise Error::new(@errno, @error) end a end
def write(arg) unless @net then error Error::CR_SERVER_GONE_ERROR end @net.write arg end
def hash_password(password) nr = 1345345333 add = 7 nr2 = 0x12345671 password.each_byte do |i| next if i == 0x20 or i == 9 nr ^= (((nr & 63) + add) * i) + (nr << 8) nr2 += (nr2 << 8) ^ nr add += i end [nr & ((1 << 31) - 1), nr2 & ((1 << 31) - 1)] end
def scramble(password, message, old_ver) return "" if password == nil or password == "" raise "old version password is not implemented" if old_ver hash_pass = hash_password password hash_message = hash_password message.slice(0,SCRAMBLE_LENGTH_323) rnd = Random::new hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1] to = [] 1.upto(SCRAMBLE_LENGTH_323) do to << ((rnd.rnd_31)+64).floor end extra = (rnd.rnd_31).floor to.map! do |t| (t ^ extra).chr end to.join end
def scramble41(password, message) return 0x00.chr if password.nil? or password.empty? buf = [0x14] s1 = Digest::SHA1.digest(password) s2 = Digest::SHA1.digest(s1) x = Digest::SHA1.digest(message + s2) (0..s1.length - 1).each {|i| buf.push(s1[i] ^ x[i])} buf.pack("C*") end
def error(errno) @errno = errno @error = Error::err errno raise Error::new(@errno, @error) end
class Result def initialize(mysql, fields, field_count, data=nil) @handle = mysql @fields = fields @field_count = field_count @data = data @current_field = 0 @current_row = 0 @eof = false @row_count = 0 end attr_accessor :eof
def data_seek(n) @current_row = n end
def fetch_field() return if @current_field >= @field_count f = @fields[@current_field] @current_field += 1 f end
def fetch_fields() @fields end
def fetch_field_direct(n) @fields[n] end
def fetch_lengths() @data ? @data[@current_row].map{|i| i ? i.length : 0} : @lengths end
def fetch_row() if @data then if @current_row >= @data.length then @handle.status = :STATUS_READY return end ret = @data[@current_row] @current_row += 1 else return if @eof ret = @handle.read_one_row @field_count if ret == nil then @eof = true return end @lengths = ret.map{|i| i ? i.length : 0} @row_count += 1 end ret end
def fetch_hash(with_table=nil) row = fetch_row return if row == nil hash = {} @fields.each_index do |i| f = with_table ? @fields[i].table+"."+@fields[i].name : @fields[i].name hash[f] = row[i] end hash end
def field_seek(n) @current_field = n end
def field_tell() @current_field end
def free() @handle.skip_result @handle = @fields = @data = nil end
def num_fields() @field_count end
def num_rows() @data ? @data.length : @row_count end
def row_seek(n) @current_row = n end
def row_tell() @current_row end
def each() while row = fetch_row do yield row end end
def each_hash(with_table=nil) while hash = fetch_hash(with_table) do yield hash end end
def inspect() "#<#{self.class}>" end
end
class Field
Field type
TYPE_DECIMAL = 0 TYPE_TINY = 1 TYPE_SHORT = 2 TYPE_LONG = 3 TYPE_FLOAT = 4 TYPE_DOUBLE = 5 TYPE_NULL = 6 TYPE_TIMESTAMP = 7 TYPE_LONGLONG = 8 TYPE_INT24 = 9 TYPE_DATE = 10 TYPE_TIME = 11 TYPE_DATETIME = 12 TYPE_YEAR = 13 TYPE_NEWDATE = 14 TYPE_ENUM = 247 TYPE_SET = 248 TYPE_TINY_BLOB = 249 TYPE_MEDIUM_BLOB = 250 TYPE_LONG_BLOB = 251 TYPE_BLOB = 252 TYPE_VAR_STRING = 253 TYPE_STRING = 254 TYPE_GEOMETRY = 255 TYPE_CHAR = TYPE_TINY TYPE_INTERVAL = TYPE_ENUM
Flag
NOT_NULL_FLAG = 1 PRI_KEY_FLAG = 2 UNIQUE_KEY_FLAG = 4 MULTIPLE_KEY_FLAG = 8 BLOB_FLAG = 16 UNSIGNED_FLAG = 32 ZEROFILL_FLAG = 64 BINARY_FLAG = 128 ENUM_FLAG = 256 AUTO_INCREMENT_FLAG = 512 TIMESTAMP_FLAG = 1024 SET_FLAG = 2048 NUM_FLAG = 32768 PART_KEY_FLAG = 16384 GROUP_FLAG = 32768 UNIQUE_FLAG = 65536
def initialize(table, org_table, name, length, type, flags, decimals, def_value, max_length) @table = table @org_table = org_table @name = name @length = length @type = type @flags = flags @decimals = decimals @def = def_value @max_length = max_length if (type <= TYPE_INT24 and (type != TYPE_TIMESTAMP or length == 14 or length == 8)) or type == TYPE_YEAR then @flags |= NUM_FLAG end end attr_reader :table, :org_table, :name, :length, :type, :flags, :decimals, :def, :max_length
def inspect() "##{self.class}:#{@name}" end
end
class Error < StandardError
Server Error
ER_HASHCHK = 1000 ER_NISAMCHK = 1001 ER_NO = 1002 ER_YES = 1003 ER_CANT_CREATE_FILE = 1004 ER_CANT_CREATE_TABLE = 1005 ER_CANT_CREATE_DB = 1006 ER_DB_CREATE_EXISTS = 1007 ER_DB_DROP_EXISTS = 1008 ER_DB_DROP_DELETE = 1009 ER_DB_DROP_RMDIR = 1010 ER_CANT_DELETE_FILE = 1011 ER_CANT_FIND_SYSTEM_REC = 1012 ER_CANT_GET_STAT = 1013 ER_CANT_GET_WD = 1014 ER_CANT_LOCK = 1015 ER_CANT_OPEN_FILE = 1016 ER_FILE_NOT_FOUND = 1017 ER_CANT_READ_DIR = 1018 ER_CANT_SET_WD = 1019 ER_CHECKREAD = 1020 ER_DISK_FULL = 1021 ER_DUP_KEY = 1022 ER_ERROR_ON_CLOSE = 1023 ER_ERROR_ON_READ = 1024 ER_ERROR_ON_RENAME = 1025 ER_ERROR_ON_WRITE = 1026 ER_FILE_USED = 1027 ER_FILSORT_ABORT = 1028 ER_FORM_NOT_FOUND = 1029 ER_GET_ERRNO = 1030 ER_ILLEGAL_HA = 1031 ER_KEY_NOT_FOUND = 1032 ER_NOT_FORM_FILE = 1033 ER_NOT_KEYFILE = 1034 ER_OLD_KEYFILE = 1035 ER_OPEN_AS_READONLY = 1036 ER_OUTOFMEMORY = 1037 ER_OUT_OF_SORTMEMORY = 1038 ER_UNEXPECTED_EOF = 1039 ER_CON_COUNT_ERROR = 1040 ER_OUT_OF_RESOURCES = 1041 ER_BAD_HOST_ERROR = 1042 ER_HANDSHAKE_ERROR = 1043 ER_DBACCESS_DENIED_ERROR = 1044 ER_ACCESS_DENIED_ERROR = 1045 ER_NO_DB_ERROR = 1046 ER_UNKNOWN_COM_ERROR = 1047 ER_BAD_NULL_ERROR = 1048 ER_BAD_DB_ERROR = 1049 ER_TABLE_EXISTS_ERROR = 1050 ER_BAD_TABLE_ERROR = 1051 ER_NON_UNIQ_ERROR = 1052 ER_SERVER_SHUTDOWN = 1053 ER_BAD_FIELD_ERROR = 1054 ER_WRONG_FIELD_WITH_GROUP = 1055 ER_WRONG_GROUP_FIELD = 1056 ER_WRONG_SUM_SELECT = 1057 ER_WRONG_VALUE_COUNT = 1058 ER_TOO_LONG_IDENT = 1059 ER_DUP_FIELDNAME = 1060 ER_DUP_KEYNAME = 1061 ER_DUP_ENTRY = 1062 ER_WRONG_FIELD_SPEC = 1063 ER_PARSE_ERROR = 1064 ER_EMPTY_QUERY = 1065 ER_NONUNIQ_TABLE = 1066 ER_INVALID_DEFAULT = 1067 ER_MULTIPLE_PRI_KEY = 1068 ER_TOO_MANY_KEYS = 1069 ER_TOO_MANY_KEY_PARTS = 1070 ER_TOO_LONG_KEY = 1071 ER_KEY_COLUMN_DOES_NOT_EXITS = 1072 ER_BLOB_USED_AS_KEY = 1073 ER_TOO_BIG_FIELDLENGTH = 1074 ER_WRONG_AUTO_KEY = 1075 ER_READY = 1076 ER_NORMAL_SHUTDOWN = 1077 ER_GOT_SIGNAL = 1078 ER_SHUTDOWN_COMPLETE = 1079 ER_FORCING_CLOSE = 1080 ER_IPSOCK_ERROR = 1081 ER_NO_SUCH_INDEX = 1082 ER_WRONG_FIELD_TERMINATORS = 1083 ER_BLOBS_AND_NO_TERMINATED = 1084 ER_TEXTFILE_NOT_READABLE = 1085 ER_FILE_EXISTS_ERROR = 1086 ER_LOAD_INFO = 1087 ER_ALTER_INFO = 1088 ER_WRONG_SUB_KEY = 1089 ER_CANT_REMOVE_ALL_FIELDS = 1090 ER_CANT_DROP_FIELD_OR_KEY = 1091 ER_INSERT_INFO = 1092 ER_INSERT_TABLE_USED = 1093 ER_NO_SUCH_THREAD = 1094 ER_KILL_DENIED_ERROR = 1095 ER_NO_TABLES_USED = 1096 ER_TOO_BIG_SET = 1097 ER_NO_UNIQUE_LOGFILE = 1098 ER_TABLE_NOT_LOCKED_FOR_WRITE = 1099 ER_TABLE_NOT_LOCKED = 1100 ER_BLOB_CANT_HAVE_DEFAULT = 1101 ER_WRONG_DB_NAME = 1102 ER_WRONG_TABLE_NAME = 1103 ER_TOO_BIG_SELECT = 1104 ER_UNKNOWN_ERROR = 1105 ER_UNKNOWN_PROCEDURE = 1106 ER_WRONG_PARAMCOUNT_TO_PROCEDURE = 1107 ER_WRONG_PARAMETERS_TO_PROCEDURE = 1108 ER_UNKNOWN_TABLE = 1109 ER_FIELD_SPECIFIED_TWICE = 1110 ER_INVALID_GROUP_FUNC_USE = 1111 ER_UNSUPPORTED_EXTENSION = 1112 ER_TABLE_MUST_HAVE_COLUMNS = 1113 ER_RECORD_FILE_FULL = 1114 ER_UNKNOWN_CHARACTER_SET = 1115 ER_TOO_MANY_TABLES = 1116 ER_TOO_MANY_FIELDS = 1117 ER_TOO_BIG_ROWSIZE = 1118 ER_STACK_OVERRUN = 1119 ER_WRONG_OUTER_JOIN = 1120 ER_NULL_COLUMN_IN_INDEX = 1121 ER_CANT_FIND_UDF = 1122 ER_CANT_INITIALIZE_UDF = 1123 ER_UDF_NO_PATHS = 1124 ER_UDF_EXISTS = 1125 ER_CANT_OPEN_LIBRARY = 1126 ER_CANT_FIND_DL_ENTRY = 1127 ER_FUNCTION_NOT_DEFINED = 1128 ER_HOST_IS_BLOCKED = 1129 ER_HOST_NOT_PRIVILEGED = 1130 ER_PASSWORD_ANONYMOUS_USER = 1131 ER_PASSWORD_NOT_ALLOWED = 1132 ER_PASSWORD_NO_MATCH = 1133 ER_UPDATE_INFO = 1134 ER_CANT_CREATE_THREAD = 1135 ER_WRONG_VALUE_COUNT_ON_ROW = 1136 ER_CANT_REOPEN_TABLE = 1137 ER_INVALID_USE_OF_NULL = 1138 ER_REGEXP_ERROR = 1139 ER_MIX_OF_GROUP_FUNC_AND_FIELDS = 1140 ER_NONEXISTING_GRANT = 1141 ER_TABLEACCESS_DENIED_ERROR = 1142 ER_COLUMNACCESS_DENIED_ERROR = 1143 ER_ILLEGAL_GRANT_FOR_TABLE = 1144 ER_GRANT_WRONG_HOST_OR_USER = 1145 ER_NO_SUCH_TABLE = 1146 ER_NONEXISTING_TABLE_GRANT = 1147 ER_NOT_ALLOWED_COMMAND = 1148 ER_SYNTAX_ERROR = 1149 ER_DELAYED_CANT_CHANGE_LOCK = 1150 ER_TOO_MANY_DELAYED_THREADS = 1151 ER_ABORTING_CONNECTION = 1152 ER_NET_PACKET_TOO_LARGE = 1153 ER_NET_READ_ERROR_FROM_PIPE = 1154 ER_NET_FCNTL_ERROR = 1155 ER_NET_PACKETS_OUT_OF_ORDER = 1156 ER_NET_UNCOMPRESS_ERROR = 1157 ER_NET_READ_ERROR = 1158 ER_NET_READ_INTERRUPTED = 1159 ER_NET_ERROR_ON_WRITE = 1160 ER_NET_WRITE_INTERRUPTED = 1161 ER_TOO_LONG_STRING = 1162 ER_TABLE_CANT_HANDLE_BLOB = 1163 ER_TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164 ER_DELAYED_INSERT_TABLE_LOCKED = 1165 ER_WRONG_COLUMN_NAME = 1166 ER_WRONG_KEY_COLUMN = 1167 ER_WRONG_MRG_TABLE = 1168 ER_DUP_UNIQUE = 1169 ER_BLOB_KEY_WITHOUT_LENGTH = 1170 ER_PRIMARY_CANT_HAVE_NULL = 1171 ER_TOO_MANY_ROWS = 1172 ER_REQUIRES_PRIMARY_KEY = 1173 ER_NO_RAID_COMPILED = 1174 ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175 ER_KEY_DOES_NOT_EXITS = 1176 ER_CHECK_NO_SUCH_TABLE = 1177 ER_CHECK_NOT_IMPLEMENTED = 1178 ER_CANT_DO_THIS_DURING_AN_TRANSACTION = 1179 ER_ERROR_DURING_COMMIT = 1180 ER_ERROR_DURING_ROLLBACK = 1181 ER_ERROR_DURING_FLUSH_LOGS = 1182 ER_ERROR_DURING_CHECKPOINT = 1183 ER_NEW_ABORTING_CONNECTION = 1184 ER_DUMP_NOT_IMPLEMENTED = 1185 ER_FLUSH_MASTER_BINLOG_CLOSED = 1186 ER_INDEX_REBUILD = 1187 ER_MASTER = 1188 ER_MASTER_NET_READ = 1189 ER_MASTER_NET_WRITE = 1190 ER_FT_MATCHING_KEY_NOT_FOUND = 1191 ER_LOCK_OR_ACTIVE_TRANSACTION = 1192 ER_UNKNOWN_SYSTEM_VARIABLE = 1193 ER_CRASHED_ON_USAGE = 1194 ER_CRASHED_ON_REPAIR = 1195 ER_WARNING_NOT_COMPLETE_ROLLBACK = 1196 ER_TRANS_CACHE_FULL = 1197 ER_SLAVE_MUST_STOP = 1198 ER_SLAVE_NOT_RUNNING = 1199 ER_BAD_SLAVE = 1200 ER_MASTER_INFO = 1201 ER_SLAVE_THREAD = 1202 ER_TOO_MANY_USER_CONNECTIONS = 1203 ER_SET_CONSTANTS_ONLY = 1204 ER_LOCK_WAIT_TIMEOUT = 1205 ER_LOCK_TABLE_FULL = 1206 ER_READ_ONLY_TRANSACTION = 1207 ER_DROP_DB_WITH_READ_LOCK = 1208 ER_CREATE_DB_WITH_READ_LOCK = 1209 ER_WRONG_ARGUMENTS = 1210 ER_NO_PERMISSION_TO_CREATE_USER = 1211 ER_UNION_TABLES_IN_DIFFERENT_DIR = 1212 ER_LOCK_DEADLOCK = 1213 ER_TABLE_CANT_HANDLE_FULLTEXT = 1214 ER_CANNOT_ADD_FOREIGN = 1215 ER_NO_REFERENCED_ROW = 1216 ER_ROW_IS_REFERENCED = 1217 ER_CONNECT_TO_MASTER = 1218 ER_QUERY_ON_MASTER = 1219 ER_ERROR_WHEN_EXECUTING_COMMAND = 1220 ER_WRONG_USAGE = 1221 ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222 ER_CANT_UPDATE_WITH_READLOCK = 1223 ER_MIXING_NOT_ALLOWED = 1224 ER_DUP_ARGUMENT = 1225 ER_USER_LIMIT_REACHED = 1226 ER_SPECIFIC_ACCESS_DENIED_ERROR = 1227 ER_LOCAL_VARIABLE = 1228 ER_GLOBAL_VARIABLE = 1229 ER_NO_DEFAULT = 1230 ER_WRONG_VALUE_FOR_VAR = 1231 ER_WRONG_TYPE_FOR_VAR = 1232 ER_VAR_CANT_BE_READ = 1233 ER_CANT_USE_OPTION_HERE = 1234 ER_NOT_SUPPORTED_YET = 1235 ER_MASTER_FATAL_ERROR_READING_BINLOG = 1236 ER_SLAVE_IGNORED_TABLE = 1237 ER_ERROR_MESSAGES = 238
Client Error
CR_MIN_ERROR = 2000 CR_MAX_ERROR = 2999 CR_UNKNOWN_ERROR = 2000 CR_SOCKET_CREATE_ERROR = 2001 CR_CONNECTION_ERROR = 2002 CR_CONN_HOST_ERROR = 2003 CR_IPSOCK_ERROR = 2004 CR_UNKNOWN_HOST = 2005 CR_SERVER_GONE_ERROR = 2006 CR_VERSION_ERROR = 2007 CR_OUT_OF_MEMORY = 2008 CR_WRONG_HOST_INFO = 2009 CR_LOCALHOST_CONNECTION = 2010 CR_TCP_CONNECTION = 2011 CR_SERVER_HANDSHAKE_ERR = 2012 CR_SERVER_LOST = 2013 CR_COMMANDS_OUT_OF_SYNC = 2014 CR_NAMEDPIPE_CONNECTION = 2015 CR_NAMEDPIPEWAIT_ERROR = 2016 CR_NAMEDPIPEOPEN_ERROR = 2017 CR_NAMEDPIPESETSTATE_ERROR = 2018 CR_CANT_READ_CHARSET = 2019 CR_NET_PACKET_TOO_LARGE = 2020 CR_EMBEDDED_CONNECTION = 2021 CR_PROBE_SLAVE_STATUS = 2022 CR_PROBE_SLAVE_HOSTS = 2023 CR_PROBE_SLAVE_CONNECT = 2024 CR_PROBE_MASTER_CONNECT = 2025 CR_SSL_CONNECTION_ERROR = 2026 CR_MALFORMED_PACKET = 2027
CLIENT_ERRORS = [ "Unknown MySQL error", "Can't create UNIX socket (%d)", "Can't connect to local MySQL server through socket '%-.64s' (%d)", "Can't connect to MySQL server on '%-.64s' (%d)", "Can't create TCP/IP socket (%d)", "Unknown MySQL Server Host '%-.64s' (%d)", "MySQL server has gone away", "Protocol mismatch. Server Version = %d Client Version = %d", "MySQL client run out of memory", "Wrong host info", "Localhost via UNIX socket", "%-.64s via TCP/IP", "Error in server handshake", "Lost connection to MySQL server during query", "Commands out of sync; You can't run this command now", "%-.64s via named pipe", "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)", "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)", "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)", "Can't initialize character set %-.64s (path: %-.64s)", "Got packet bigger than 'max_allowed_packet'", "Embedded server", "Error on SHOW SLAVE STATUS:", "Error on SHOW SLAVE HOSTS:", "Error connecting to slave:", "Error connecting to master:", "SSL connection error", "Malformed packet" ]
def initialize(errno, error) @errno = errno @error = error super error end attr_reader :errno, :error
def Error::err(errno) CLIENT_ERRORS[errno - Error::CR_MIN_ERROR] end
end
class Net def initialize(sock) @sock = sock @pkt_nr = 0 end
def clear() @pkt_nr = 0 end
def read() buf = [] len = nil @sock.sync = false while len == nil or len == MAX_PACKET_LENGTH do a = @sock.read(4) len = a[0]+a[1]_256+a[2]_256*256 pkt_nr = a[3] if @pkt_nr != pkt_nr then raise "Packets out of order: #{@pkt_nr}<>#{pkt_nr}" end @pkt_nr = @pkt_nr + 1 & 0xff buf << @sock.read(len) end @sock.sync = true buf.join rescue errno = Error::CR_SERVER_LOST raise Error::new(errno, Error::err(errno)) end
def write(data) if data.is_a? Array then data = data.join end @sock.sync = false ptr = 0 while data.length >= MAX_PACKET_LENGTH do @sock.write Net::int3str(MAX_PACKET_LENGTH)+@pkt_nr.chr+data[ptr, MAX_PACKET_LENGTH] @pkt_nr = @pkt_nr + 1 & 0xff ptr += MAX_PACKET_LENGTH end @sock.write Net::int3str(data.length-ptr)+@pkt_nr.chr+data[ptr .. -1] @pkt_nr = @pkt_nr + 1 & 0xff @sock.sync = true @sock.flush rescue errno = Error::CR_SERVER_LOST raise Error::new(errno, Error::err(errno)) end
def close() @sock.close end
def Net::int2str(n) [n].pack("v") end
def Net::int3str(n) [n%256, n>>8].pack("cv") end
def Net::int4str(n) [n].pack("V") end
end
class Random def initialize(seed1, seed2) @max_value = 0x3FFFFFFF @seed1 = seed1 % @max_value @seed2 = seed2 % @max_value end
def rnd() @seed1 = (@seed1*3+@seed2) % @max_value @seed2 = (@seed1+@seed2+33) % @max_value @seed1.to_f / @max_value end
end
end
class << Mysql def init() Mysql::new :INIT end
def real_connect(_args) Mysql::new(_args) end alias :connect :real_connect
def finalizer(net) proc { net.clear begin net.write(Mysql::COM_QUIT.chr) net.close rescue # Ignore IOError if socket is already closed. end } end
def escape_string(str) str.gsub(/([\0\n\r\032\'\"])/) do case $1 when "\0" then "\0" when "\n" then "\n" when "\r" then "\r" when "\032" then "\Z" else "\"+$1 end end end alias :quote :escape_string
def get_client_info() Mysql::VERSION end alias :client_info :get_client_info
def debug(str) raise "not implemented" end end
# for compatibility
#
MysqlRes = Mysql::Result MysqlField = Mysql::Field MysqlError = Mysql::Error
Reply to this email directly or view it on GitHubhttps://github.com/luislavena/mysql-gem/issues/10#issuecomment-13660686.
The mysql.rb
you provided here is nowhere this repository or the gem released.
Closing this out.
If you find the project that host this file, please report this issue there.
https://github.com/trevorturk/eldorado
That is what I know this project as. written by Trevor Truk, but no longer supported by him El Dorado - a bulletin board / IM Chat system.
I apologize for my ignorance and error in posting it in your project. Can't say why that happened, other than the mysql part may have enticed me.
Originally discovered at: http://bugs.ruby-lang.org/issues/5017
2.1.0 (May 31st, 2008) Activerecord MySQL adapter /home/username/rails_apps/appname/vendor/rails/activerecord/lib/active_record/vendor/mysql.rb
No required 0 byte at end of string.
immediately after: def real_connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, socket=nil, flag=nil) I inserted: db = db + "\0" unless db == nil
for the purpose of appending the required 0 byte
Fixed it, for me, in an old and brittle app stuck with various further host restrictions.
Hoping to document issue and fix for the next poor sob.