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.
Fixed in master.
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.
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
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.
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
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