Fixnum/String randomly changing type

Hi,

I am seeing some odd behavior that look to me to like it could be a bug
in Ruby. Being new to the language, however, I wanted to see if there
was another explanation. I am using Ruby 1.8.4 on an Intel Mac. The
code at the bottom of this message is an excerpt from a class in a
larger script. It is using DBI to pull 10 fields from a MySQL database.
The first 9 are integers (tinyint(4) in the database) and the last is a
string (varchar(255) in the database). When I run the below program as
is, the puts outputs:

Info[0] class: String
Info[0] value: 0
Info[0] class: String
Info[0] value: 0
.
.
.

However, if I uncomment the ‘info.each’ line, I get:

Info[0] class: Fixnum
Info[0] value: 0
0
Info[0] class: Fixnum
Info[0] value: 0
0
.
.
.

So, it seams that just printing out the value in an ‘each’ loop causes
it to change from a String to a Fixnum throughout the code segment. The
break statement makes no difference (it just reduces the output for the
purpose of posting here). It is my understanding that the MySQL driver
for DBI should coerce the objects to numbers since that is their type in
the database. However, regardless of what type they start as, I don’t
understand how adding an each loop with a print in it can change the
type. Also, I can’t seem to reproduce this behavior in a small test
program. I do know that the database queries are successful and are
returning the proper values. Does anyone have any ideas? Is this a bug
or is there some subtlety of type inferencing that I am missing?

@sthVulnID.fetch do |id|
ids.push(id[0])
begin
@sthVulnInfo.execute(id[0])
rescue DBI::DatabaseError => e
puts “An error occurred getting vulnerability info”
puts “Variables: name:”#{name}" k:"#{k}" v:"#{v}""
puts “Error code: #{e.err}”
puts “Error message: #{e.errstr}”
exit
end
info = @sthVulnInfo.fetch_array

  puts "Info is: #{info[0].class}"

info.each { |newval| puts “#{newval.class}”; break }

  newVuln.addInfo('osvdb-location', 'physical') if ( info[0] == 1 )
  newVuln.addInfo('osvdb-location', 'local') if ( info[1] == 1 )
  newVuln.addInfo('osvdb-location', 'remote') if ( info[2] == 1 )
  newVuln.addInfo('osvdb-location', 'dialup') if ( info[3] == 1 )
  newVuln.addInfo('osvdb-location', 'unknown') if ( info[4] == 1 )
  newVuln.addInfo('osvdb-impact', 'confidentiality') if ( info[5] == 

1 )
newVuln.addInfo(‘osvdb-impact’, ‘integrity’) if ( info[6] == 1 )
newVuln.addInfo(‘osvdb-impact’, ‘availability’) if ( info[7] == 1
)
newVuln.addInfo(‘osvdb-impact’, ‘unknown’) if ( info[8] == 1 )
newVuln.addInfo(‘osvdb-title’, info[9])
end

  puts "Info is: #{info[0].class}"

info.each { |newval| puts “#{newval.class}”; break }

One small correction… to match the output I gave, the commented out
line should read:

info.each { |newval| puts “#{newval}”; break }

The behavior is the same in both cases, going from String to Fixnum when
the ‘each’ loop is uncommented.

Sam W. wrote:

Info[0] class: String
Info[0] value: 0
Info[0] class: String
Info[0] value: 0

And the below program is …?

Paul L. wrote:

Sam W. wrote:

Info[0] class: String
Info[0] value: 0
Info[0] class: String
Info[0] value: 0

And the below program is …?

The program (or program fragment actually) at the bottom of my first
message. Here it is again:

@sthVulnID.fetch do |id|
ids.push(id[0])
begin
@sthVulnInfo.execute(id[0])
rescue DBI::DatabaseError => e
puts “An error occurred getting vulnerability info”
puts “Variables: name:”#{name}" k:"#{k}" v:"#{v}""
puts “Error code: #{e.err}”
puts “Error message: #{e.errstr}”
exit
end
info = @sthVulnInfo.fetch_array

  puts "Info is: #{info[0].class}"

info.each { |newval| puts “#{newval}”; break }

  newVuln.addInfo('osvdb-location', 'physical') if ( info[0] == 1 )
  newVuln.addInfo('osvdb-location', 'local') if ( info[1] == 1 )
  newVuln.addInfo('osvdb-location', 'remote') if ( info[2] == 1 )
  newVuln.addInfo('osvdb-location', 'dialup') if ( info[3] == 1 )
  newVuln.addInfo('osvdb-location', 'unknown') if ( info[4] == 1 )
  newVuln.addInfo('osvdb-impact', 'confidentiality') if ( info[5] ==

1 )
newVuln.addInfo(‘osvdb-impact’, ‘integrity’) if ( info[6] == 1 )
newVuln.addInfo(‘osvdb-impact’, ‘availability’) if ( info[7] == 1
)
newVuln.addInfo(‘osvdb-impact’, ‘unknown’) if ( info[8] == 1 )
newVuln.addInfo(‘osvdb-title’, info[9])
end

On 9/26/06, Sam W. [email protected] wrote:

the ‘each’ loop is uncommented.
This is a documented bug. The fix for those crashes made it into
1.8.5. I recommend you upgrade.

Searching ruby-core will probably give you more results. (don’t have a
reference # handy right now).

(However, I also seem to still get crashes when doing rdoc processing.
I haven’t been able to pin it down for a report yet though.)

Brian.

Brian M. wrote:

On 9/26/06, Sam W. [email protected] wrote:

the ‘each’ loop is uncommented.
This is a documented bug. The fix for those crashes made it into
1.8.5. I recommend you upgrade.

Searching ruby-core will probably give you more results. (don’t have a
reference # handy right now).

(However, I also seem to still get crashes when doing rdoc processing.
I haven’t been able to pin it down for a report yet though.)

Brian.

Thanks Brian. Upgrading to 1.8.5 appears to have fixed the problem.

On 9/26/06, Sam W. [email protected] wrote:

I am seeing some odd behavior that look to me to like it could be a bug
in Ruby. Being new to the language, however, I wanted to see if there
was another explanation. I am using Ruby 1.8.4 on an Intel Mac. The
code at the bottom of this message is an excerpt from a class in a
larger script. It is using DBI to pull 10 fields from a MySQL database.
The first 9 are integers (tinyint(4) in the database) and the last is a
string (varchar(255) in the database). When I run the below program as
is, the puts outputs:

My guess, based on what you’re seeing, is that something special is
being done on the #each by either DBI or the DBD driver for MySQL. It
sees that it’s really a Fixnum value that it’s supposed to be
returning, and converts it for you.

-austin