Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Mysql::Error: SAVEPOINT active_record_1 does not exist: ROLLBACK TO SAVEPOINT active_record_1

#1925

Hi,

I'm upgrading a Rails 2.1.1 app to 2.3 rc1 and encountering this quite a bit in my specs.

Trying to workaround it now, but thought I'd point it out. I'm surprised I haven't found mention of it anywhere else just yet.

Reported by Nicholas Faiz · February 10th, 2009 @ 12:26 AM

State: invalid
Milestone: 2.x
Assigned to: nobody
Importance: none

Activity

  1. Nicholas Faiz
    Nicholas Faiz

    Sorry, a bit more information for ths ticket.

    It seems to be happening on AR exectute statements calls to TRUNCATE:

    e.g.

    
    
    
    ActiveRecord::Base.connection.execute("TRUNCATE factsheets")
    
    
    
    
    

    February 10th, 2009 @ 12:36 AM

  2. Jonathan Viney
    Jonathan Viney

    Can you show more of your logs? Are the savepoints being defined?

    February 10th, 2009 @ 03:01 PM

  3. Nicholas Faiz
    Nicholas Faiz

    Unfortunately yesterday was also the day I chose to clean up my huge log files.

    If you can't replicate it in your environment, let me know and I'll restore the code and try to generate a log file for you. If you can replicate it there's probably not much point in my doing it.

    Thanks for the quick response.

    Regards, Nicholas

    February 10th, 2009 @ 10:49 PM

  4. Jonathan Viney
    Jonathan Viney

    A basic test seems to work ok:

    
    Person::Note.transaction do
      Person::Note.transaction :requires_new => true do
        ActiveRecord::Base.connection.execute("TRUNCATE person_notes")
      end
    end
    

    Runs:

    
    SQL (0.2ms)  BEGIN
    SQL (0.1ms)  SAVEPOINT active_record_1
    SQL (3.0ms)  TRUNCATE person_notes
    SQL (0.4ms)  RELEASE SAVEPOINT active_record_1
    SQL (0.2ms)  COMMIT
    

    February 11th, 2009 @ 11:06 AM

  5. Nicholas Faiz
  6. Jonathan Viney
    Jonathan Viney

    It appears that TRUNCATE is a DDL statement, http://dev.mysql.com/doc/refman/..., and therefore causes an implicit commit. The docs already warn against using DDL statements inside savepoints.

    
    Person::Note.transaction do
      ActiveRecord::Base.connection.execute("TRUNCATE person_notes")
      Person::Note.transaction :requires_new => true do
      end
    end
    

    Can you simply use DELETE FROM instead of TRUNCATE?

    February 11th, 2009 @ 11:56 AM

  7. Nicholas Faiz
    Nicholas Faiz

    Short answer - yes.

    This code was appearing in our test code, and was probably added quickly without thought. It's not something we need supported. I wanted to point out this error was occurring though.

    Thanks for the quick response.

    N.

    February 11th, 2009 @ 12:02 PM

  8. Jonathan Viney
    Jonathan Viney

    No worries, let's close this off then.

    February 11th, 2009 @ 12:07 PM

  9. Jeremy Kemper
    Jeremy Kemper
    • State changed from new to invalid

    February 11th, 2009 @ 06:07 PM

  10. Nicholas Faiz
    Nicholas Faiz

    Is it possible to close this as something like 'Wont's Fix' instead of invalid? This is a real issue.

    February 11th, 2009 @ 07:07 PM

  11. Elia Schito
    Elia Schito

    Found the same issue while running some rspec tests, but...

    in activerecord-2.3.1/lib/active_record/transactions.rb:182 there's the following note:

    === Caveats

    If you're on MySQL, then do not use DDL operations in nested transactions blocks that are emulated with savepoints. That is, do not execute statements like 'CREATE TABLE' inside such blocks. This is because MySQL automatically releases all savepoints upon executing a DDL operation. When #transaction is finished and tries to release the savepoint it created earlier, a database error will occur because the savepoint has already been automatically released. The following example demonstrates the problem: Model.connection.transaction do # BEGIN

    Model.connection.transaction(:requires_new => true) do  # CREATE SAVEPOINT active_record_1
      Model.connection.create_table(...)                    # active_record_1 now automatically released
    end                                                     # RELEASE savepoint active_record_1
                                                            # ^^^^ BOOM! database error!
    
    

    end

    (posted this just to help people that will google to here)

    March 13th, 2009 @ 12:28 PM

  12. Hongli Lai
    Hongli Lai

    I'm not sure how this should best be fixed, so for now I've documented this caveat in docrails: http://github.com/lifo/docrails/...

    March 24th, 2009 @ 04:06 PM

  13. stanislav.pogrebnyak (at gmail)
    stanislav.pogrebnyak (at gmail)

    This bug appears on shoulda tests too. 20% of my tests fail with that strange error. How can I fix it?
    Non transactional tests are unacceptable cos them are slow. What should I do?

    June 15th, 2009 @ 08:00 AM

  14. Jeremy Kemper
    Jeremy Kemper

    stanislav, do not use DDL statements in your tests or code if you want to use transactions to rollback fixtures.

    This is not a "won't fix" -- it's simply not fixable because most databases do not support transactional DDL statements.

    June 17th, 2009 @ 03:03 AM

  15. stanislav.pogrebnyak (at gmail)
    stanislav.pogrebnyak (at gmail)

    Uh, I was dreaming about "do nothing during migration to rails 2.3.x", Actually, I heave a strong filling that this errors cos shoulda contexts, but thnx anyway. Will digg my code.

    June 19th, 2009 @ 07:37 AM

  16. Rob Aldred
    Rob Aldred

    Just wanted to add some comments that might be useful for people experiencing this with Rspec + Cucumber
    basically... turn off transaction fixtures... its the only way I have found to avoid this error in your tests.

    Then use a global before(:each) in the Rspec & Cucumber config files/helpers that uses DatabaseCleaner

    Rspec

    ruby

    config.after(:each) {

    DatabaseCleaner.clean
    

    }

    Cucumber

    ruby

    After('@no-transaction') do DatabaseCleaner.clean end

    August 7th, 2009 @ 05:51 PM

  17. Rob Aldred
    Rob Aldred

    sorry syntax fail - no preview sucks :(

      # rspec
      config.after(:each) {
        DatabaseCleaner.clean
      }
    

    # cucumber After do

    DatabaseCleaner.clean
    

    end

    August 7th, 2009 @ 05:53 PM