Shouldn''t update_all be updating lock_version? As you can see from my console session below, it is upating the record (changed running attribute to true and returned 1 to show 1 recored was updated). But it did not increment lock_version. And optimistic locking is working correctly otherwise. As you can see below, lock version = 562 before and after the update_all call but it is incremented to 563 when I save() the object. Am I missing something here? Thanks, Don>> jobs = Job.find(:all, :conditions => [''id = 10''])=> [#<Job:0xb73f9ea4 @attributes={"status"=>"1", "server_id"=>nil, "running"=>"0", "poller_id"=>"10", "lock_version"=>"562", "response_time"=>"8", "id"=>"10", "next_run_at"=>"2006-07-06 13:43:33", "last_run_at"=>"2006-07-06 13:42:33", "late"=>"0.532686"}>]>> puts jobs[0].running, jobs[0].lock_versionfalse 562 => nil>> Job.update_all([''running = ?'', true], [''id in (?)'', jobs.map { |j| j.id}])=> 1>> jobs = Job.find(:all, :conditions => [''id = 10''])=> [#<Job:0xb73e835c @attributes={"status"=>"1", "server_id"=>nil, "running"=>"1", "poller_id"=>"10", "lock_version"=>"562", "response_time"=>"8", "id"=>"10", "next_run_at"=>"2006-07-06 13:43:33", "last_run_at"=>"2006-07-06 13:42:33", "late"=>"0.532686"}>]>> puts jobs[0].running, jobs[0].lock_versiontrue 562 => nil>> j = Job.find(10)=> #<Job:0xb73e2cb8 @attributes={"status"=>"1", "server_id"=>nil, "running"=>"1", "poller_id"=>"10", "lock_version"=>"562", "response_time"=>"8", "id"=>"10", "next_run_at"=>"2006-07-06 13:43:33", "last_run_at"=>"2006-07-06 13:42:33", "late"=>"0.532686"}>>> j.running = false=> false>> j.save=> true>> j=> #<Job:0xb73e2cb8 @attributes={"status"=>"1", "server_id"=>nil, "running"=>false, "poller_id"=>"10", "lock_version"=>563, "response_time"=>"8", "id"=>"10", "next_run_at"=>"2006-07-06 13:43:33", "last_run_at"=>"2006-07-06 13:42:33", "late"=>"0.532686"}, @errors=#<ActiveRecord::Errors:0xb73dfe8c @base=#<Job:0xb73e2cb8 ...>, @errors={}>>>> j.reload=> #<Job:0xb73e2cb8 @server=nil, @attributes={"status"=>"1", "server_id"=>nil, "running"=>"0", "poller_id"=>"10", "lock_version"=>"563", "response_time"=>"8", "id"=>"10", "next_run_at"=>"2006-07-06 13:43:33", "last_run_at"=>"2006-07-06 13:42:33", "late"=>"0.532686"}, @poller=nil, @errors=#<ActiveRecord::Errors:0xb73dfe8c @base=#<Job:0xb73e2cb8 ...>, @errors={}>>>>-- Posted via http://www.ruby-forum.com/.
Don Stocks wrote: Comments anyone? Unless I''m making a newbie mistake this is a significant bug. - Don -- Posted via http://www.ruby-forum.com/.
Don Stocks wrote: OK. I''m NOT an SQL expert, but I think I know why this is the case. It is because of the way update_all queries are structured. For example: UPDATE jobs SET jobs.running = 1 WHERE (id in (10,11,12)) There is no reference to the lock_version column. Please know that I''m a total SQL hack. But why couldn''t we do this instead? Assuming: +----+--------------+ | id | lock_version | +----+--------------+ | 10 | 1340 | | 11 | 1333 | | 12 | 807 | +----+--------------+ UPDATE jobs SET jobs.running = 1 WHERE (id in (10,11,12) AND lock_version in (1340, 1333, 807)); This seems to do the trick. Don''t even ask me how optimistic locking exception handling would work for this kind of update. I''ll leave that to the professionals. ;) Thoughts? - Don BTW : At the very least, we need the update_all documentation to reflect the fact it''s not honoring optimistic locking. And if it''s too tricky to add support for it then I might have to look into another approach. Maybe a stored proc. -- Posted via http://www.ruby-forum.com/.
Don -- " UPDATE jobs SET jobs.running = 1 WHERE (id in (10,11,12)) ... UPDATE jobs SET jobs.running = 1 WHERE (id in (10,11,12) AND lock_version in (1340, 1333, 807)); " I think you want update jobs set jobs.running = 1, jobs.lock_version = jobs.lock_version + 1 where (id = 10 and lock_version = 1340) or (id = 11 and lock_version = 1333) or (id = 12 and lock_version = 807) With a begin transaction somewhere and a rollback if this doesn''t update 3 rows. Others and Don -- So, I have a record with a lock_version field and Rails did not increment the lock_version field prior to saving the record on disk. The ''save'' method does not maintain lock_version. I don''t understand what the point is in having magic fields if they are going to work magically. Chuck -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060718/ad3bcf80/attachment.html
Chuck Simmons wrote:> I think you want > > update jobs set jobs.running = 1, jobs.lock_version = jobs.lock_version > + 1 > where (id = 10 and lock_version = 1340) > or (id = 11 and lock_version = 1333) > or (id = 12 and lock_version = 807) > > > With a begin transaction somewhere and a rollback if this doesn''t update > 3 rows. >Chuck, Yes. Thank you. You are exactly right. I was so focused on setting the running field I completely missed the part of the update that was part and parcel to post! Thank you for the correction! Wouldn''t this also work? UPDATE jobs SET jobs.running = 1, jobs.lock_version = jobs.lock_version + 1 WHERE (id in (10,11,12) AND lock_version in (1340, 1333, 807)); If so I guess it''s a matter of which is more efficient. Like I mentioned. I''m certainly not a SQL guy! If any SQL gurus out there can provide a litte guidence here and the Rails community can verify that update_all should increment lock_version, then we can work on a patch. - Don -- Posted via http://www.ruby-forum.com/.