diff options
Diffstat (limited to 'activerecord')
10 files changed, 78 insertions, 27 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 8c99a3929e..a4ba956477 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,25 @@ ## Rails 4.0.0 (unreleased) ## +* Explain only normal CRUD sql (select / update / insert / delete). + Fix problem that explains unexplainable sql. Closes #7544 #6458. + + *kennyj* + +* Fix `find_in_batches` when primary_key is set other than id. + You can now use this method with the primary key which is not integer-based. + + Example: + + class Post < ActiveRecord::Base + self.primary_key = :title + end + + Post.find_in_batches(:start => 'My First Post') do |batch| + batch.each { |post| post.author.greeting } + end + + *Toshiyuki Kawanishi* + * You can now override the generated accessor methods for stored attributes and reuse the original behavior with `read_store_attribute` and `write_store_attribute`, which are counterparts to `read_attribute` and `write_attribute`. diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index c8c3fcb22a..32e3c7f5d8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -163,8 +163,8 @@ module ActiveRecord else within_new_transaction(options) { yield } end - rescue Exception => error - raise unless error.is_a?(ActiveRecord::Rollback) + rescue ActiveRecord::Rollback + # rollbacks are silently swallowed end def within_new_transaction(options = {}) #:nodoc: @@ -176,7 +176,7 @@ module ActiveRecord ensure begin commit_transaction unless error - rescue Exception => e + rescue Exception rollback_transaction raise end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 60f01c297e..8a073bf878 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -111,7 +111,7 @@ module ActiveRecord inddef = row[3] oid = row[4] - columns = Hash[query(<<-SQL, "Columns for index #{row[0]} on #{table_name}")] + columns = Hash[query(<<-SQL, "SCHEMA")] SELECT a.attnum, a.attname FROM pg_attribute a WHERE a.attrelid = #{oid} @@ -252,7 +252,7 @@ module ActiveRecord if pk && sequence quoted_sequence = quote_table_name(sequence) - select_value <<-end_sql, 'Reset sequence' + select_value <<-end_sql, 'SCHEMA' SELECT setval('#{quoted_sequence}', (SELECT COALESCE(MAX(#{quote_column_name pk})+(SELECT increment_by FROM #{quoted_sequence}), (SELECT min_value FROM #{quoted_sequence})) FROM #{quote_table_name(table)}), false) end_sql end @@ -262,7 +262,7 @@ module ActiveRecord def pk_and_sequence_for(table) #:nodoc: # First try looking for a sequence with a dependency on the # given table's primary key. - result = query(<<-end_sql, 'PK and serial sequence')[0] + result = query(<<-end_sql, 'SCHEMA')[0] SELECT attr.attname, seq.relname FROM pg_class seq, pg_attribute attr, @@ -283,7 +283,7 @@ module ActiveRecord # If that fails, try parsing the primary key's default value. # Support the 7.x and 8.0 nextval('foo'::text) as well as # the 8.1+ nextval('foo'::regclass). - result = query(<<-end_sql, 'PK and custom sequence')[0] + result = query(<<-end_sql, 'SCHEMA')[0] SELECT attr.attname, CASE WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index b6dd2e17f4..4a48812807 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -403,7 +403,7 @@ module ActiveRecord table_name, row['name'], row['unique'] != 0, - exec_query("PRAGMA index_info('#{row['name']}')", "Columns for index #{row['name']} on #{table_name}").map { |col| + exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col| col['name'] }) end diff --git a/activerecord/lib/active_record/explain_subscriber.rb b/activerecord/lib/active_record/explain_subscriber.rb index d5ba343b4c..0f927496fb 100644 --- a/activerecord/lib/active_record/explain_subscriber.rb +++ b/activerecord/lib/active_record/explain_subscriber.rb @@ -18,8 +18,9 @@ module ActiveRecord # On the other hand, we want to monitor the performance of our real database # queries, not the performance of the access to the query cache. IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN CACHE) + EXPLAINED_SQLS = /\A\s*(select|update|delete|insert)/i def ignore_payload?(payload) - payload[:exception] || IGNORED_PAYLOADS.include?(payload[:name]) + payload[:exception] || IGNORED_PAYLOADS.include?(payload[:name]) || payload[:sql] !~ EXPLAINED_SQLS end ActiveSupport::Notifications.subscribe("sql.active_record", new) diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index 4d14506965..d32048cce1 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -36,12 +36,12 @@ module ActiveRecord # want multiple workers dealing with the same processing queue. You can # make worker 1 handle all the records between id 0 and 10,000 and # worker 2 handle from 10,000 and beyond (by setting the +:start+ - # option on that worker). + # option on that worker). You can also use non-integer-based primary keys + # if start point is set. # # It's not possible to set the order. That is automatically set to - # ascending on the primary key ("id ASC") to make the batch ordering - # work. This also mean that this method only works with integer-based - # primary keys. You can't set the limit either, that's used to control + # ascending on the primary key (e.g. "id ASC") to make the batch ordering + # work. You can't set the limit either, that's used to control # the batch sizes. # # Person.where("age > 21").find_in_batches do |group| @@ -62,7 +62,8 @@ module ActiveRecord ActiveRecord::Base.logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size") end - start = options.delete(:start).to_i + start = options.delete(:start) + start ||= 0 batch_size = options.delete(:batch_size) || 1000 relation = relation.reorder(batch_order).limit(batch_size) @@ -70,7 +71,7 @@ module ActiveRecord while records.any? records_size = records.size - primary_key_offset = records.last.id + primary_key_offset = records.last.send(primary_key) yield records diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index b9d480d9ce..b25d169038 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1619,26 +1619,32 @@ class BasicsTest < ActiveRecord::TestCase def test_silence_sets_log_level_to_error_in_block original_logger = ActiveRecord::Base.logger - log = StringIO.new - ActiveRecord::Base.logger = ActiveSupport::Logger.new(log) - ActiveRecord::Base.logger.level = Logger::DEBUG - ActiveRecord::Base.silence do - ActiveRecord::Base.logger.warn "warn" - ActiveRecord::Base.logger.error "error" + + assert_deprecated do + log = StringIO.new + ActiveRecord::Base.logger = ActiveSupport::Logger.new(log) + ActiveRecord::Base.logger.level = Logger::DEBUG + ActiveRecord::Base.silence do + ActiveRecord::Base.logger.warn "warn" + ActiveRecord::Base.logger.error "error" + end + assert_equal "error\n", log.string end - assert_equal "error\n", log.string ensure ActiveRecord::Base.logger = original_logger end def test_silence_sets_log_level_back_to_level_before_yield original_logger = ActiveRecord::Base.logger - log = StringIO.new - ActiveRecord::Base.logger = ActiveSupport::Logger.new(log) - ActiveRecord::Base.logger.level = Logger::WARN - ActiveRecord::Base.silence do + + assert_deprecated do + log = StringIO.new + ActiveRecord::Base.logger = ActiveSupport::Logger.new(log) + ActiveRecord::Base.logger.level = Logger::WARN + ActiveRecord::Base.silence do + end + assert_equal Logger::WARN, ActiveRecord::Base.logger.level end - assert_equal Logger::WARN, ActiveRecord::Base.logger.level ensure ActiveRecord::Base.logger = original_logger end diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index cdd4b49042..3b4ff83725 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -124,4 +124,15 @@ class EachTest < ActiveRecord::TestCase assert_equal special_posts_ids, posts.map(&:id) end + def test_find_in_batches_should_use_any_column_as_primary_key + title_order_posts = Post.order('title asc') + start_title = title_order_posts.first.title + + posts = [] + PostWithTitlePrimaryKey.find_in_batches(:batch_size => 1, :start => start_title) do |batch| + posts.concat(batch) + end + + assert_equal title_order_posts.map(&:id), posts.map(&:id) + end end diff --git a/activerecord/test/cases/explain_subscriber_test.rb b/activerecord/test/cases/explain_subscriber_test.rb index 91e1df91cd..b425967678 100644 --- a/activerecord/test/cases/explain_subscriber_test.rb +++ b/activerecord/test/cases/explain_subscriber_test.rb @@ -38,6 +38,13 @@ if ActiveRecord::Base.connection.supports_explain? end end + def test_collects_nothing_if_unexplained_sqls + with_queries([]) do |queries| + SUBSCRIBER.finish(nil, nil, :name => 'SQL', :sql => 'SHOW max_identifier_length') + assert queries.empty? + end + end + def with_queries(queries) Thread.current[:available_queries_for_explain] = queries yield queries diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index c995f59a15..9858f68c4a 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -186,3 +186,8 @@ class SpecialPostWithDefaultScope < ActiveRecord::Base self.table_name = 'posts' default_scope { where(:id => [1, 5,6]) } end + +class PostWithTitlePrimaryKey < ActiveRecord::Base + self.table_name = 'posts' + self.primary_key = :title +end |