r3886@sedna: jeremy | 2005-11-07 03:09:59 -0800
r3944@sedna: jeremy | 2005-11-09 01:29:56 -0800 Upgrade bundled ruby-mysql 0.2.4 with mysql411 shim (see #440) to ruby-mysql0.2.6 with a patchset for 4.1 protocol support. Local change [301] is now apart of the main driver; reapplied local change [2182]. Removed GC.start fromResult.free. git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@2947 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
bb4c32e2b5
commit
44591ffb71
|
@ -1,5 +1,10 @@
|
|||
*SVN*
|
||||
|
||||
* Upgrade bundled ruby-mysql 0.2.4 with mysql411 shim (see #440) to ruby-mysql
|
||||
0.2.6 with a patchset for 4.1 protocol support. Local change [301] is now a
|
||||
part of the main driver; reapplied local change [2182]. Removed GC.start from
|
||||
Result.free. [tommy@tmtm.org, akuroda@gmail.com, Doug Fales <doug.fales@gmail.com>, Jeremy Kemper]
|
||||
|
||||
* Correct handling of complex order clauses with SQL Server limit emulation. #2770 [Tom Ward <tom@popdog.net>, Matt B.]
|
||||
|
||||
* Correct whitespace problem in Oracle default column value parsing. #2788 [rick@rickbradley.com]
|
||||
|
|
|
@ -14,7 +14,6 @@ module ActiveRecord
|
|||
# Only use the supplied backup Ruby/MySQL driver if no driver is already in place
|
||||
begin
|
||||
require 'active_record/vendor/mysql'
|
||||
require 'active_record/vendor/mysql411'
|
||||
# The ruby version of mysql returns null fields in each_hash
|
||||
ConnectionAdapters::MysqlAdapter.null_values_in_each_hash = true
|
||||
rescue LoadError
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
# $Id: mysql.rb,v 1.1 2004/02/24 15:42:29 webster132 Exp $
|
||||
# $Id: mysql.rb,v 1.24 2005/02/12 11:37:15 tommy Exp $
|
||||
#
|
||||
# Copyright (C) 2003 TOMITA Masahiro
|
||||
# Copyright (C) 2003-2005 TOMITA Masahiro
|
||||
# tommy@tmtm.org
|
||||
#
|
||||
|
||||
class Mysql
|
||||
|
||||
VERSION = "4.0-ruby-0.2.4"
|
||||
VERSION = "4.0-ruby-0.2.5"
|
||||
|
||||
require "socket"
|
||||
require "digest/sha1"
|
||||
|
||||
MAX_PACKET_LENGTH = 256*256*256-1
|
||||
MAX_ALLOWED_PACKET = 1024*1024*1024
|
||||
|
@ -51,11 +52,15 @@ class Mysql
|
|||
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
|
||||
|
@ -115,19 +120,37 @@ class Mysql
|
|||
@server_capabilities, = a.slice!(0,2).unpack("v")
|
||||
end
|
||||
if a.size >= 16 then
|
||||
@server_language, @server_status = a.unpack("cv")
|
||||
@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
|
||||
data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+(user||"")+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)
|
||||
|
||||
if !@server_capabilities & PROTO_AUTH41
|
||||
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 then
|
||||
data << "\0"+db
|
||||
if PROTO_AUTH41
|
||||
data << db+"\0"
|
||||
else
|
||||
data << "\0"+db
|
||||
end
|
||||
@db = db.dup
|
||||
end
|
||||
write data
|
||||
read
|
||||
ObjectSpace.define_finalizer(self, Mysql.finalizer(@net))
|
||||
self
|
||||
end
|
||||
alias :connect :real_connect
|
||||
|
@ -182,7 +205,11 @@ class Mysql
|
|||
end
|
||||
|
||||
def change_user(user="", passwd="", db="")
|
||||
if !@server_capabilities & PROTO_AUTH41
|
||||
data = user+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)+"\0"+db
|
||||
else
|
||||
data = user+"\0"+ scramble41(passwd, @scramble_buff)
|
||||
end
|
||||
command COM_CHANGE_USER, data
|
||||
@user = user
|
||||
@passwd = passwd
|
||||
|
@ -243,7 +270,11 @@ class Mysql
|
|||
|
||||
def list_fields(table, field=nil)
|
||||
command COM_FIELD_LIST, "#{table}\0#{field}", true
|
||||
if !@server_capabilities & PROTO_AUTH41
|
||||
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
|
||||
|
@ -253,7 +284,11 @@ class Mysql
|
|||
def list_processes()
|
||||
data = command COM_PROCESS_INFO
|
||||
@field_count = get_length data
|
||||
if !@server_capabilities & PROTO_AUTH41
|
||||
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
|
||||
|
@ -311,7 +346,11 @@ class Mysql
|
|||
|
||||
def read_one_row(field_count)
|
||||
data = read
|
||||
return if data[0] == 254 and data.length == 1
|
||||
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
|
||||
|
@ -363,7 +402,11 @@ class Mysql
|
|||
end
|
||||
else
|
||||
@extra_info = get_length(data, true)
|
||||
if !@server_capabilities & PROTO_AUTH41
|
||||
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
|
||||
|
@ -373,6 +416,7 @@ class Mysql
|
|||
def unpack_fields(data, long_flag_protocol)
|
||||
ret = []
|
||||
data.each do |f|
|
||||
if !@server_capabilities & PROTO_AUTH41
|
||||
table = org_table = f[0]
|
||||
name = f[1]
|
||||
length = f[2][0]+f[2][1]*256+f[2][2]*256*256
|
||||
|
@ -386,8 +430,22 @@ class Mysql
|
|||
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
|
||||
ret << Field::new(table, org_table, name, length, type, flags, decimals, def_value, max_length)
|
||||
end
|
||||
end
|
||||
ret
|
||||
end
|
||||
|
||||
|
@ -489,6 +547,19 @@ class Mysql
|
|||
to.join
|
||||
end
|
||||
|
||||
def scramble41(password, message)
|
||||
if password.length != 0
|
||||
buf = [0x14]
|
||||
s1 = Digest::SHA1.new(password).digest
|
||||
s2 = Digest::SHA1.new(s1).digest
|
||||
x = Digest::SHA1.new(message + s2).digest
|
||||
(0..s1.length - 1).each {|i| buf.push(s1[i] ^ x[i])}
|
||||
buf.pack("C*")
|
||||
else
|
||||
0x00.chr
|
||||
end
|
||||
end
|
||||
|
||||
def error(errno)
|
||||
@errno = errno
|
||||
@error = Error::err errno
|
||||
|
@ -574,7 +645,6 @@ class Mysql
|
|||
def free()
|
||||
@handle.skip_result
|
||||
@handle = @fields = @data = nil
|
||||
GC::start
|
||||
end
|
||||
|
||||
def num_fields()
|
||||
|
@ -1023,8 +1093,8 @@ class Mysql
|
|||
@sock.sync = true
|
||||
buf.join
|
||||
rescue
|
||||
errno = Error::CR_SERVER_LOST
|
||||
raise Error::new(errno, Error::err(errno))
|
||||
errno = Error::CR_SERVER_LOST
|
||||
raise Error::new(errno, Error::err(errno))
|
||||
end
|
||||
|
||||
def write(data)
|
||||
|
@ -1043,8 +1113,8 @@ class Mysql
|
|||
@sock.sync = true
|
||||
@sock.flush
|
||||
rescue
|
||||
errno = Error::CR_SERVER_LOST
|
||||
raise Error::new(errno, Error::err(errno))
|
||||
errno = Error::CR_SERVER_LOST
|
||||
raise Error::new(errno, Error::err(errno))
|
||||
end
|
||||
|
||||
def close()
|
||||
|
@ -1091,6 +1161,13 @@ class << Mysql
|
|||
end
|
||||
alias :connect :real_connect
|
||||
|
||||
def finalizer(net)
|
||||
proc {
|
||||
net.clear
|
||||
net.write Mysql::COM_QUIT.chr
|
||||
}
|
||||
end
|
||||
|
||||
def escape_string(str)
|
||||
str.gsub(/([\0\n\r\032\'\"\\])/) do
|
||||
case $1
|
||||
|
|
|
@ -1,311 +0,0 @@
|
|||
#
|
||||
# mysq411.rb - 0.1 - Matt Mower <self@mattmower.com>
|
||||
#
|
||||
# The native Ruby MySQL client (mysql.rb) by Tomita Masahiro does not (yet) handle the new MySQL
|
||||
# protocol introduced in MySQL 4.1.1. This protocol introduces a new authentication scheme as
|
||||
# well as modifications to the client/server exchanges themselves.
|
||||
#
|
||||
# mysql411.rb modifies the Mysql class to add MySQL 4.1.x support. It modifies the connection
|
||||
# algorithm to detect a 4.1.1 server and respond with the new authentication scheme, otherwise using
|
||||
# the original one. Similarly for the changes to packet structures and field definitions, etc...
|
||||
#
|
||||
# It redefines serveral methods which behave differently depending upon the server context. The
|
||||
# way I have implemented this is to alias the old method, create a new alternative method, and redefine
|
||||
# the original method as a selector which calls the appropriate method based upon the server version.
|
||||
# There may have been a neater way to do this.
|
||||
#
|
||||
# In general I've tried not to change the original code any more than necessary, i.e. even where I
|
||||
# redefine a method I have made the smallest number of changes possible, rather than rewriting from
|
||||
# scratch.
|
||||
#
|
||||
# *Caveat Lector* This code passes all current ActiveRecord unit tests however this is no guarantee that
|
||||
# full & correct MySQL 4.1 support has been achieved.
|
||||
#
|
||||
|
||||
require 'digest/sha1'
|
||||
|
||||
#
|
||||
# Extend the Mysql class to work with MySQL 4.1.1+ servers. After version
|
||||
# 4.1.1 the password hashing function (and some other connection details) have
|
||||
# changed rendering the previous Mysql class unable to connect:
|
||||
#
|
||||
#
|
||||
|
||||
class Mysql
|
||||
CLIENT_PROTOCOL_41 = 512
|
||||
CLIENT_SECURE_CONNECTION = 32768
|
||||
|
||||
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 || host == "localhost" ) && defined? UNIXSocket
|
||||
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)
|
||||
|
||||
# Store the version number components for speedy comparison
|
||||
version, ostag = @server_version.split( /-/, 2 )
|
||||
@use_411 = (version.strip >= '4.1.1')
|
||||
|
||||
@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.unpack("cv")
|
||||
end
|
||||
|
||||
# Set the flags we'll send back to the server
|
||||
flag = 0 if flag == nil
|
||||
flag |= @client_flag | CLIENT_CAPABILITIES
|
||||
flag |= CLIENT_CONNECT_WITH_DB if db
|
||||
|
||||
if @use_411
|
||||
# In 4.1.1+ the seed comes in two parts which must be combined
|
||||
a.slice!( 0, 16 )
|
||||
seed_part_2 = a.slice!( 0, 12 );
|
||||
@scramble_buff << seed_part_2
|
||||
|
||||
flag |= CLIENT_FOUND_ROWS
|
||||
flag |= CLIENT_PROTOCOL_41
|
||||
flag |= CLIENT_SECURE_CONNECTION if @server_capabilities & CLIENT_SECURE_CONNECTION;
|
||||
|
||||
if db && @server_capabilities & CLIENT_CONNECT_WITH_DB != 0
|
||||
@db = db.dup
|
||||
end
|
||||
|
||||
scrambled_password = scramble411( passwd, @scramble_buff, @protocol_version==9 )
|
||||
data = make_client_auth_packet_41( flag, user, scrambled_password, db )
|
||||
else
|
||||
scrambled_password = scramble( passwd, @scramble_buff, @protocol_version == 9 )
|
||||
data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+(user||"")+"\0"+scrambled_password
|
||||
if db and @server_capabilities & CLIENT_CONNECT_WITH_DB != 0 then
|
||||
data << "\0"+db
|
||||
@db = db.dup
|
||||
end
|
||||
end
|
||||
|
||||
write data
|
||||
read
|
||||
self
|
||||
end
|
||||
alias :connect :real_connect
|
||||
|
||||
# Pack the authentication information into depending upon whether an initial database has
|
||||
# been specified
|
||||
def make_client_auth_packet_41( flag, user, password, db )
|
||||
if db && @server_capabilities & CLIENT_CONNECT_WITH_DB != 0
|
||||
template = "VVcx23a#{user.size+1}cA#{password.size}a#{db.size+1}"
|
||||
else
|
||||
template = "VVcx23a#{user.size+1}cA#{password.size}x"
|
||||
end
|
||||
|
||||
[ flag, @max_allowed_packet, @server_language, user, password.size, password, db ].pack( template )
|
||||
end
|
||||
|
||||
# SERVER: public_seed=create_random_string()
|
||||
# send(public_seed)
|
||||
#
|
||||
# CLIENT: recv(public_seed)
|
||||
# hash_stage1=sha1("password")
|
||||
# hash_stage2=sha1(hash_stage1)
|
||||
# reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
|
||||
#
|
||||
# #this three steps are done in scramble()
|
||||
#
|
||||
# send(reply)
|
||||
#
|
||||
#
|
||||
# SERVER: recv(reply)
|
||||
# hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
|
||||
# candidate_hash2=sha1(hash_stage1)
|
||||
# check(candidate_hash2==hash_stage2)
|
||||
def scramble411( password, seed, old_ver )
|
||||
return "" if password == nil or password == ""
|
||||
raise "old version password is not implemented" if old_ver
|
||||
|
||||
# print "Seed Bytes = "
|
||||
# seed.each_byte { |b| print "0x#{b.to_s( 16 )}, " }
|
||||
# puts
|
||||
|
||||
stage1 = Digest::SHA1.digest( password )
|
||||
stage2 = Digest::SHA1.digest( stage1 )
|
||||
|
||||
dgst = Digest::SHA1.new
|
||||
dgst << seed
|
||||
dgst << stage2
|
||||
stage3 = dgst.digest
|
||||
|
||||
# stage1.zip( stage3 ).map { |a, b| (a ^ b).chr }.join
|
||||
scrambled = ( 0 ... stage3.size ).map { |i| stage3[i] ^ stage1[i] }
|
||||
scrambled = scrambled.map { |x| x.chr }
|
||||
scrambled.join
|
||||
end
|
||||
|
||||
def change_user(user="", passwd="", db="")
|
||||
scrambled_password = @use_411 ? scramble411( passwd, @scramble_buff, @protocol_version==9 ) : scramble( passwd, @scramble_buff, @protocol_version==9 )
|
||||
data = user+"\0"+scrambled_password+"\0"+db
|
||||
command COM_CHANGE_USER, data
|
||||
@user = user
|
||||
@passwd = passwd
|
||||
@db = db
|
||||
end
|
||||
|
||||
#
|
||||
# The 4.1 protocol changed the length of the END packet
|
||||
#
|
||||
alias_method :old_read_one_row, :read_one_row
|
||||
|
||||
def read_one_row( field_count )
|
||||
if @use_411
|
||||
read_one_row_41( field_count )
|
||||
else
|
||||
old_read_one_row( field_count )
|
||||
end
|
||||
end
|
||||
|
||||
def read_one_row_41( field_count )
|
||||
data = read
|
||||
return if data[0] == 254 and data.length < 9
|
||||
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
|
||||
|
||||
#
|
||||
# The 4.1 protocol changed the length of the END packet
|
||||
#
|
||||
alias_method :old_skip_result, :skip_result
|
||||
|
||||
def skip_result
|
||||
if @use_411
|
||||
skip_result_41
|
||||
else
|
||||
old_skip_result
|
||||
end
|
||||
end
|
||||
|
||||
def skip_result_41()
|
||||
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
|
||||
|
||||
# The field description structure is changed for the 4.1 protocol passing
|
||||
# more data and a different packing form. NOTE: The 4.1 protocol now passes
|
||||
# back a "catalog" name for each field which is a new feature. Since AR has
|
||||
# nowhere to put it I'm throwing it away. Possibly this is not the best
|
||||
# idea?
|
||||
#
|
||||
alias_method :old_unpack_fields, :unpack_fields
|
||||
|
||||
def unpack_fields( data, long_flag_protocol )
|
||||
if @use_411
|
||||
unpack_fields_41( data, long_flag_protocol )
|
||||
else
|
||||
old_unpack_fields( data, long_flag_protocol )
|
||||
end
|
||||
end
|
||||
|
||||
def unpack_fields_41( data, long_flag_protocol )
|
||||
ret = []
|
||||
|
||||
data.each do |f|
|
||||
catalog_name = f[0]
|
||||
database_name = f[1]
|
||||
table_name_alias = f[2]
|
||||
table_name = f[3]
|
||||
column_name_alias = f[4]
|
||||
column_name = f[5]
|
||||
|
||||
charset = f[6][0] + f[6][1]*256
|
||||
length = f[6][2] + f[6][3]*256 + f[6][4]*256*256 + f[6][5]*256*256*256
|
||||
type = f[6][6]
|
||||
flags = f[6][7] + f[6][8]*256
|
||||
decimals = f[6][9]
|
||||
def_value = f[7]
|
||||
max_length = 0
|
||||
|
||||
ret << Field::new(table_name, table_name, column_name_alias, length, type, flags, decimals, def_value, max_length)
|
||||
end
|
||||
ret
|
||||
end
|
||||
|
||||
# In this instance the read_query_result method in mysql is bound to read 5 field parameters which
|
||||
# is expanded to 7 in the 4.1 protocol. So in this case we redefine this entire method in order
|
||||
# to write "read_rows 7" instead of "read_rows 5"!
|
||||
#
|
||||
alias_method :old_read_query_result, :read_query_result
|
||||
|
||||
def read_query_result
|
||||
if @use_411
|
||||
read_query_result_41
|
||||
else
|
||||
old_read_query_result
|
||||
end
|
||||
end
|
||||
|
||||
def read_query_result_41
|
||||
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)
|
||||
fields = read_rows 7
|
||||
@fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0)
|
||||
@status = :STATUS_GET_RESULT
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
|
||||
# Get rid of GC.start in #free.
|
||||
class Result
|
||||
def free
|
||||
@handle.skip_result
|
||||
@handle = @fields = @data = nil
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue