1. 06 11月, 2015 1 次提交
    • S
      Correctly deallocate prepared statements if we fail inside a transaction · 50c53340
      Sam Davies 提交于
      - Addresses issue #12330
      
      Overview
      ========
      
      Cached postgres prepared statements become invalidated if the schema
      changes in a way that it affects the returned result.
      
      Examples:
      - adding or removing a column then doing a 'SELECT *'
      - removing the foo column  then doing a 'SELECT bar.foo'
      
      In normal operation this isn't a problem, we can rescue the error,
      deallocate the prepared statement and re-issue the command.
      
      However in PostgreSQL transactions, once any command fails, the
      transaction becomes 'poisoned' and any subsequent commands will raise
      InFailedSQLTransaction.
      
      This includes DEALLOCATE statements, so the default deallocation
      strategy instead of removing the cached prepared statement instead
      raises InFailedSQLTransaction.
      
      Why this is bad
      ===============
      
      1. InFailedSQLTransaction is a fairly cryptic error and doesn't
      communicate any useful information about what has actually gone wrong.
      2. In the naive implementation the prepared statement never gets
      deallocated - it stays alive for the length of the session taking up
      memory on the postgres server.
      3. It is unsafe to retry the transaction because the bad prepared
      statement is still in the cache and we would see the exact same failure
      repeated.
      
      Solution
      ========
      
      If we are outside a transaction we can continue to handle these failures
      gracefully in the usual way.
      
      Inside a transaction instead of issuing a DEALLOCATE command that will
      certainly fail, we now raise
      ActiveRecord::PreparedStatementCacheExpired.
      
      This can be handled further up the stack, notably inside
      TransactionManager#within_new_transaction. Here we can make sure to
      first rollback the transaction, then safely issue DEALLOCATE statements
      to invalidate the rest of the cached prepared statements.
      
      This also allows the user (or some gem) the opportunity to catch this error and
      voluntarily retry the transaction if a schema change causes the prepared
      statement cache to become invalidated.
      
      Because the outdated statement has been deallocated, we can expect the
      transaction to succeed on the second try.
      50c53340
  2. 17 3月, 2015 1 次提交
    • B
      Closes rails/rails#18864: Renaming transactional fixtures to transactional tests · 09658635
      Brandon Weiss 提交于
      I’m renaming all instances of `use_transcational_fixtures` to
      `use_transactional_tests` and “transactional fixtures” to
      “transactional tests”.
      
      I’m deprecating `use_transactional_fixtures=`. So anyone who is
      explicitly setting this will get a warning telling them to use
      `use_transactional_tests=` instead.
      
      I’m maintaining backwards compatibility—both forms will work.
      `use_transactional_tests` will check to see if
      `use_transactional_fixtures` is set and use that, otherwise it will use
      itself. But because `use_transactional_tests` is a class attribute
      (created with `class_attribute`) this requires a little bit of hoop
      jumping. The writer method that `class_attribute` generates defines a
      new reader method that return the value being set. Which means we can’t
      set the default of `true` using `use_transactional_tests=` as was done
      previously because that won’t take into account anyone using
      `use_transactional_fixtures`. Instead I defined the reader method
      manually and it checks `use_transactional_fixtures`. If it was set then
      it should be used, otherwise it should return the default, which is
      `true`. If someone uses `use_transactional_tests=` then it will
      overwrite the backwards-compatible method with whatever they set.
      09658635
  3. 14 1月, 2014 2 次提交
  4. 12 1月, 2014 1 次提交
  5. 29 9月, 2012 1 次提交