Bug 677807 - Object-valued fields in persisting classes are write-once
Summary: Object-valued fields in persisting classes are write-once
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise MRG
Classification: Red Hat
Component: ruby-rhubarb
Version: 1.3
Hardware: Unspecified
OS: Unspecified
low
low
Target Milestone: 2.0
: ---
Assignee: Will Benton
QA Contact: Tomas Rusnak
URL:
Whiteboard:
Depends On:
Blocks: 693778
TreeView+ depends on / blocked
 
Reported: 2011-02-15 21:41 UTC by Will Benton
Modified: 2011-06-23 15:42 UTC (History)
4 users (show)

Fixed In Version: rhubarb-0.3.0-1
Doc Type: Bug Fix
Doc Text:
C: The rhubarb library supports serializing arbitrary Ruby objects as members of persistent objects, but these fields could only be assigned to once. C: This behavior is unexpected and undesirable for clients of rhubarb other than wallaby. F: Object-valued fields can now be updated via the assignment operator, just like other database-backed fields of persisting objects. R: Object-valued fields can be updated an arbitrary number of times. Summary: It is now possible to use the Rhubarb persistence library to declare persisting classes with mutable object-valued fields; previously, object-valued fields could only be written once per object.
Clone Of:
Environment:
Last Closed: 2011-06-23 15:42:30 UTC
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Product Errata RHEA-2011:0889 0 normal SHIPPED_LIVE Red Hat Enterprise MRG Grid 2.0 Release 2011-06-23 15:35:53 UTC

Description Will Benton 2011-02-15 21:41:08 UTC
Description of problem:

The rhubarb library supports serializing arbitrary Ruby objects as members of persistent objects.  However, this support does not extend to updating object-valued fields in persistent objects.

Version-Release number of selected component (if applicable):

ruby-rhubarb-0.2.7

How reproducible:

Enter the following code into an irb session:

---snip---
require 'rhubarb/rhubarb'

# Create a rhubarb class like this:

class Foo
  include Rhubarb::Persisting
  declare_column :ls, :object
end

Rhubarb::Persistence::open(":memory:")
Foo.create_table

# Then make an instance of that class and manipulate its ls member

f = Foo.create(:ls=>[1,2,3])
f.ls = f.ls.reverse
f.ls == [3,2,1]  # should be true
---snip---

Actual results:

The assignment in the penultimate line will fail, either silently or with an exception.

Expected results:

The assignment in the penultimate line should update the persistent object appropriately.

Comment 1 Will Benton 2011-02-15 21:45:28 UTC
Fixed in master.

Comment 2 Will Benton 2011-02-15 21:45:28 UTC
    Technical note added. If any revisions are required, please edit the "Technical Notes" field
    accordingly. All revisions will be proofread by the Engineering Content Services team.
    
    New Contents:
C:  The rhubarb library supports serializing arbitrary Ruby objects as members of persistent objects, but these fields could only be assigned to once.
C:  This behavior is unexpected and undesirable for clients of rhubarb other than wallaby.
F:  Object-valued fields can now be updated via the assignment operator, just like other database-backed fields of persisting objects.
R:  Object-valued fields can be updated an arbitrary number of times.

Summary:  It is now possible to use the Rhubarb persistence library to declare persisting classes with mutable object-valued fields; previously, object-valued fields could only be written once per object.

Comment 5 Tomas Rusnak 2011-05-04 15:06:52 UTC
Reproduced on RHEL5/x86_64:

# rpm -q ruby-rhubarb
ruby-rhubarb-0.2.7-1.el5

# irb
irb(main):001:0> require 'rhubarb/rhubarb'
=> true
irb(main):002:0> 
irb(main):003:0* # Create a rhubarb class like this:
irb(main):004:0* 
irb(main):005:0* class Foo
irb(main):006:1>   include Rhubarb::Persisting
irb(main):007:1>   declare_column :ls, :object
irb(main):008:1> end
=> #<Proc:0x00002b70065ec8c8@/usr/lib/ruby/site_ruby/1.8/rhubarb/classmixins.rb:175>
irb(main):009:0> 
irb(main):010:0* Rhubarb::Persistence::open(":memory:")
=> #<SQLite3::Database:0x2b7009f64c40 @driver=#<SQLite3::Driver::Native::Driver:0x2b7009f64b00 @callback_data={}, @trace={}, @busy_handler={}, @authorizer={}>, @transaction_active=false, @closed=false, @handle=#<SWIG::TYPE_p_sqlite3:0x2b7009f54ea8>, @translator=nil, @statement_factory=SQLite3::Statement, @type_translation=true, @results_as_hash=true>
irb(main):011:0> Foo.create_table
=> []
irb(main):012:0> 
irb(main):013:0* # Then make an instance of that class and manipulate its ls member
irb(main):014:0* 
irb(main):015:0* f = Foo.create(:ls=>[1,2,3])
=> #<Foo:0x2b7009f0c108 @updated=1304525095659959, @row_id=1, @created=1304525095659959, @expired_after=1304525095661447, @tuple={"row_id"=>1, 0=>1, 1=>1304525095659959, 2=>1304525095659959, 3=>"x\332\323\325\325U\340\322U0\004b# 6\346\002\000\025\255\002M", "ls"=>"x\332\323\325\325U\340\322U0\004b# 6\346\002\000\025\255\002M", "created"=>1304525095659959, "updated"=>1304525095659959}, @backed=true>
irb(main):016:0> f.ls = f.ls.reverse
SQLite3::SQLException: database table is locked
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/errors.rb:62:in `check'
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/resultset.rb:56:in `check'
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/resultset.rb:48:in `commence'
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/resultset.rb:38:in `initialize'
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/statement.rb:135:in `new'
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/statement.rb:135:in `execute'
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/statement.rb:159:in `execute!'
	from /usr/lib/ruby/site_ruby/1.8/rhubarb/persistence.rb:19:in `do_query'
	from /usr/lib/ruby/site_ruby/1.8/rhubarb/persisting.rb:122:in `update'
	from /usr/lib/ruby/site_ruby/1.8/rhubarb/classmixins.rb:177:in `ls='
	from (irb):16
irb(main):017:0> f.ls == [3,2,1]  # should be true
=> false

Comment 6 Tomas Rusnak 2011-05-04 15:12:19 UTC
Retested on all supported platforms x86,x86_64/RHEL5,RHEL6:

#  rpm -q ruby-rhubarb
ruby-rhubarb-0.3.0-2.el6.noarch

# irb
irb(main):001:0> require 'rhubarb/rhubarb'
=> true
irb(main):002:0> 
irb(main):003:0* # Create a rhubarb class like this:
irb(main):004:0* 
irb(main):005:0* class Foo
irb(main):006:1>   include Rhubarb::Persisting
irb(main):007:1>   declare_column :ls, :object
irb(main):008:1> end
=> #<Proc:0x00007f51f8112a00@/usr/lib/ruby/site_ruby/1.8/rhubarb/classmixins.rb:181>
irb(main):009:0> 
irb(main):010:0* Rhubarb::Persistence::open(":memory:")
=> #<SQLite3::Database:0x7f51f80a8330 @translator=nil, @statement_factory=SQLite3::Statement, @type_translation=true, @results_as_hash=true, @driver=#<SQLite3::Driver::Native::Driver:0x7f51f80a81f0 @authorizer={}, @callback_data={}, @trace={}, @busy_handler={}>, @transaction_active=false, @closed=false, @handle=#<SWIG::TYPE_p_sqlite3:0x7f51f807fde0>>
irb(main):011:0> Foo.create_table
=> []
irb(main):012:0> 
irb(main):013:0* # Then make an instance of that class and manipulate its ls member
irb(main):014:0* 
irb(main):015:0* f = Foo.create(:ls=>[1,2,3])
=> #<Foo:0x7f51f7392c18 @tuple={"row_id"=>1, 0=>1, 1=>1304525240081866, 2=>1304525240081866, 3=>"x\332\323\325\325U\340\322U0\004b# 6\346\002\000\025\255\002M", "ls"=>"x\332\323\325\325U\340\322U0\004b# 6\346\002\000\025\255\002M", "updated"=>1304525240081866, "created"=>1304525240081866}, @backed=true, @updated=1304525240081866, @row_id=1, @created=1304525240081866, @expired_after=1304525240091020>
irb(main):016:0> f.ls = f.ls.reverse
=> [3, 2, 1]
irb(main):017:0> f.ls == [3,2,1]  # should be true
=> true

Looks good on RHEL6 systems.

# rpm -q ruby-rhubarb
ruby-rhubarb-0.3.0-2.el5

# irb
irb(main):001:0> require 'rhubarb/rhubarb'
=> true
irb(main):002:0> 
irb(main):003:0* # Create a rhubarb class like this:
irb(main):004:0* 
irb(main):005:0* class Foo
irb(main):006:1>   include Rhubarb::Persisting
irb(main):007:1>   declare_column :ls, :object
irb(main):008:1> end
=> #<Proc:0x00002b3b87734fb8@/usr/lib/ruby/site_ruby/1.8/rhubarb/classmixins.rb:181>
irb(main):009:0> 
irb(main):010:0* Rhubarb::Persistence::open(":memory:")
=> #<SQLite3::Database:0x2b3b8b0ac6b0 @driver=#<SQLite3::Driver::Native::Driver:0x2b3b8b0ac570 @callback_data={}, @trace={}, @busy_handler={}, @authorizer={}>, @transaction_active=false, @closed=false, @handle=#<SWIG::TYPE_p_sqlite3:0x2b3b8b09c490>, @translator=nil, @statement_factory=SQLite3::Statement, @type_translation=true, @results_as_hash=true>
irb(main):011:0> Foo.create_table
=> []
irb(main):012:0> 
irb(main):013:0* # Then make an instance of that class and manipulate its ls member
irb(main):014:0* 
irb(main):015:0* f = Foo.create(:ls=>[1,2,3])
=> #<Foo:0x2b3b8b04fb40 @backed=true, @tuple={"row_id"=>1, 0=>1, 1=>1304525309659463, 2=>1304525309659463, 3=>"x\332\323\325\325U\340\322U0\004b# 6\346\002\000\025\255\002M", "ls"=>"x\332\323\325\325U\340\322U0\004b# 6\346\002\000\025\255\002M", "created"=>1304525309659463, "updated"=>1304525309659463}, @updated=1304525309659463, @row_id=1, @created=1304525309659463, @expired_after=1304525309660828>
irb(main):016:0> f.ls = f.ls.reverse
SQLite3::SQLException: database table is locked
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/errors.rb:62:in `check'
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/resultset.rb:56:in `check'
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/resultset.rb:48:in `commence'
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/resultset.rb:38:in `initialize'
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/statement.rb:135:in `new'
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/statement.rb:135:in `execute'
	from /usr/lib/ruby/site_ruby/1.8/sqlite3/statement.rb:159:in `execute!'
	from /usr/lib/ruby/site_ruby/1.8/rhubarb/persistence.rb:19:in `do_query'
	from /usr/lib/ruby/site_ruby/1.8/rhubarb/persisting.rb:126:in `update'
	from /usr/lib/ruby/site_ruby/1.8/rhubarb/classmixins.rb:184:in `ls='
	from (irb):16
irb(main):017:0> f.ls == [3,2,1]  # should be true
=> false

Testing script failed on both RHEL5 systems - x86 and x86_64.

Comment 7 Tomas Rusnak 2011-05-04 15:21:53 UTC
Bad test script used for RHEL5, retested with repaired one:

# irb
irb(main):001:0> #!/bin/ruby
irb(main):002:0* 
irb(main):003:0* require 'rhubarb/rhubarb'
=> true
irb(main):004:0> 
irb(main):005:0* # Create a rhubarb class like this:
irb(main):006:0* 
irb(main):007:0* class Foo
irb(main):008:1>   include Rhubarb::Persisting
irb(main):009:1>   declare_column :ls, :object
irb(main):010:1> end
=> #<Proc:0x00002af8c359cc70@/usr/lib/ruby/site_ruby/1.8/rhubarb/classmixins.rb:181>
irb(main):011:0> 
irb(main):012:0* Rhubarb::Persistence::open(":memory:", :default, false)
=> #<SQLite3::Database:0x2af8c6f13300 @driver=#<SQLite3::Driver::Native::Driver:0x2af8c6f131c0 @callback_data={}, @trace={}, @busy_handler={}, @authorizer={}>, @transaction_active=false, @closed=false, @handle=#<SWIG::TYPE_p_sqlite3:0x2af8c6f02be0>, @translator=nil, @statement_factory=SQLite3::Statement, @type_translation=true, @results_as_hash=true>
irb(main):013:0> #Rhubarb::Persistence::open(":memory:")
irb(main):014:0* Foo.create_table
=> []
irb(main):015:0> 
irb(main):016:0* # Then make an instance of that class and manipulate its ls member
irb(main):017:0* 
irb(main):018:0* f = Foo.create(:ls=>[1,2,3])
=> #<Foo:0x2af8c6ead168 @backed=true, @tuple={"row_id"=>1, 0=>1, 1=>1304526044537869, 2=>1304526044537869, 3=>"x\332\323\325\325U\340\322U0\004b# 6\346\002\000\025\255\002M", "ls"=>"x\332\323\325\325U\340\322U0\004b# 6\346\002\000\025\255\002M", "created"=>1304526044537869, "updated"=>1304526044537869}, @updated=1304526044537869, @row_id=1, @created=1304526044537869, @expired_after=1304526044539326>
irb(main):019:0> f.ls = f.ls.reverse
=> [3, 2, 1]
irb(main):020:0> f.ls == [3,2,1]  # should be true
=> true

>>> VERIFIED

Comment 8 errata-xmlrpc 2011-06-23 15:42:30 UTC
An advisory has been issued which should help the problem
described in this bug report. This report is therefore being
closed with a resolution of ERRATA. For more information
on therefore solution and/or where to find the updated files,
please follow the link below. You may reopen this bug report
if the solution does not work for you.

http://rhn.redhat.com/errata/RHEA-2011-0889.html


Note You need to log in before you can comment on or make changes to this bug.