aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md20
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb2
-rw-r--r--activerecord/lib/active_record/explain_subscriber.rb3
-rw-r--r--activerecord/lib/active_record/relation/batches.rb13
-rw-r--r--activerecord/test/cases/base_test.rb30
-rw-r--r--activerecord/test/cases/batches_test.rb11
-rw-r--r--activerecord/test/cases/explain_subscriber_test.rb7
-rw-r--r--activerecord/test/models/post.rb5
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