aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb8
-rw-r--r--activerecord/lib/active_record/attribute_methods/dirty.rb8
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb4
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb4
-rw-r--r--activerecord/lib/active_record/core.rb16
-rw-r--r--activerecord/lib/active_record/persistence.rb9
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb2
-rw-r--r--activerecord/lib/active_record/table_metadata.rb6
-rw-r--r--activerecord/lib/active_record/transactions.rb18
-rw-r--r--activerecord/lib/arel/visitors/oracle.rb48
-rw-r--r--activerecord/lib/arel/visitors/oracle12.rb57
-rw-r--r--activerecord/lib/arel/visitors/to_sql.rb58
12 files changed, 82 insertions, 156 deletions
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 46532f651e..342d9e7a5a 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -36,13 +36,7 @@ module ActiveRecord
def preloaded_records
return @preloaded_records if defined?(@preloaded_records)
- return [] if owner_keys.empty?
- # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
- # Make several smaller queries if necessary or make one query if the adapter supports it
- slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
- @preloaded_records = slices.flat_map do |slice|
- records_for(slice)
- end
+ @preloaded_records = owner_keys.empty? ? [] : records_for(owner_keys)
end
private
diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index 444568562b..a43ebdf60d 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -167,12 +167,8 @@ module ActiveRecord
end
def write_attribute_without_type_cast(attr_name, value)
- name = attr_name.to_s
- if self.class.attribute_alias?(name)
- name = self.class.attribute_alias(name)
- end
- result = super(name, value)
- clear_attribute_change(name)
+ result = super
+ clear_attribute_change(attr_name)
result
end
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index c787fb6a94..0562327a9a 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -27,9 +27,7 @@ module ActiveRecord
# to a date object, like Date.new(2004, 12, 12)).
def read_attribute(attr_name, &block)
name = attr_name.to_s
- if self.class.attribute_alias?(name)
- name = self.class.attribute_alias(name)
- end
+ name = self.class.attribute_aliases[name] || name
name = @primary_key if name == "id" && @primary_key
_read_attribute(name, &block)
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index 6a54bd2fc2..1c63b553d0 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -31,9 +31,7 @@ module ActiveRecord
# turned into +nil+.
def write_attribute(attr_name, value)
name = attr_name.to_s
- if self.class.attribute_alias?(name)
- name = self.class.attribute_alias(name)
- end
+ name = self.class.attribute_aliases[name] || name
name = @primary_key if name == "id" && @primary_key
_write_attribute(name, value)
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 068ebf3c09..dfd33d3dd7 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -268,7 +268,8 @@ module ActiveRecord
end
def arel_attribute(name, table = arel_table) # :nodoc:
- name = attribute_alias(name) if attribute_alias?(name)
+ name = name.to_s
+ name = attribute_aliases[name] || name
table[name]
end
@@ -316,7 +317,7 @@ module ActiveRecord
# # Instantiates a single new object
# User.new(first_name: 'Jamie')
def initialize(attributes = nil)
- self.class.define_attribute_methods
+ @new_record = true
@attributes = self.class._default_attributes.deep_dup
init_internals
@@ -353,12 +354,10 @@ module ActiveRecord
# +attributes+ should be an attributes object, and unlike the
# `initialize` method, no assignment calls are made per attribute.
def init_with_attributes(attributes, new_record = false) # :nodoc:
- init_internals
-
@new_record = new_record
@attributes = attributes
- self.class.define_attribute_methods
+ init_internals
yield self if block_given?
@@ -403,7 +402,7 @@ module ActiveRecord
@new_record = true
@destroyed = false
- @_start_transaction_state = {}
+ @_start_transaction_state = nil
@transaction_state = nil
super
@@ -574,9 +573,10 @@ module ActiveRecord
@destroyed = false
@marked_for_destruction = false
@destroyed_by_association = nil
- @new_record = true
- @_start_transaction_state = {}
+ @_start_transaction_state = nil
@transaction_state = nil
+
+ self.class.define_attribute_methods
end
def initialize_internals_callback
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 1ff7ee4d89..adfd564695 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -664,8 +664,13 @@ module ActiveRecord
raise ActiveRecordError, "cannot update a new record" if new_record?
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
+ attributes = attributes.transform_keys do |key|
+ name = key.to_s
+ self.class.attribute_aliases[name] || name
+ end
+
attributes.each_key do |key|
- verify_readonly_attribute(key.to_s)
+ verify_readonly_attribute(key)
end
id_in_database = self.id_in_database
@@ -853,7 +858,7 @@ module ActiveRecord
attribute_names = timestamp_attributes_for_update_in_model
attribute_names |= names.map!(&:to_s).map! { |name|
- self.class.attribute_alias?(name) ? self.class.attribute_alias(name) : name
+ self.class.attribute_aliases[name] || name
}
unless attribute_names.empty?
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index f30428d0a5..c03ca7f1e7 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1178,7 +1178,7 @@ module ActiveRecord
end
def arel_column(field)
- field = klass.attribute_alias(field) if klass.attribute_alias?(field)
+ field = klass.attribute_aliases[field] || field
from = from_clause.name || from_clause.value
if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb
index b67479fb6a..073866b894 100644
--- a/activerecord/lib/active_record/table_metadata.rb
+++ b/activerecord/lib/active_record/table_metadata.rb
@@ -12,9 +12,9 @@ module ActiveRecord
def resolve_column_aliases(hash)
new_hash = hash.dup
- hash.each do |key, _|
- if (key.is_a?(Symbol)) && klass.attribute_alias?(key)
- new_hash[klass.attribute_alias(key)] = new_hash.delete(key)
+ hash.each_key do |key|
+ if key.is_a?(Symbol) && new_key = klass.attribute_aliases[key.to_s]
+ new_hash[new_key] = new_hash.delete(key)
end
end
new_hash
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index 49a8206c84..bf781b23eb 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -386,14 +386,15 @@ module ActiveRecord
# Save the new record state and id of a record so it can be restored later if a transaction fails.
def remember_transaction_record_state
- @_start_transaction_state.reverse_merge!(
+ @_start_transaction_state ||= {
id: id,
new_record: @new_record,
destroyed: @destroyed,
attributes: @attributes,
frozen?: frozen?,
- )
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
+ level: 0
+ }
+ @_start_transaction_state[:level] += 1
remember_new_record_before_last_commit
end
@@ -407,22 +408,21 @@ module ActiveRecord
# Clear the new record state and id of a record.
def clear_transaction_record_state
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
+ return unless @_start_transaction_state
+ @_start_transaction_state[:level] -= 1
force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
end
# Force to clear the transaction record state.
def force_clear_transaction_record_state
- @_start_transaction_state.clear
+ @_start_transaction_state = nil
@transaction_state = nil
end
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
def restore_transaction_record_state(force_restore_state = false)
- unless @_start_transaction_state.empty?
- transaction_level = (@_start_transaction_state[:level] || 0) - 1
- if transaction_level < 1 || force_restore_state
- restore_state = @_start_transaction_state
+ if restore_state = @_start_transaction_state
+ if force_restore_state || restore_state[:level] <= 1
@new_record = restore_state[:new_record]
@destroyed = restore_state[:destroyed]
@attributes = restore_state[:attributes].map do |attr|
diff --git a/activerecord/lib/arel/visitors/oracle.rb b/activerecord/lib/arel/visitors/oracle.rb
index 500974dff5..f96bf65ee5 100644
--- a/activerecord/lib/arel/visitors/oracle.rb
+++ b/activerecord/lib/arel/visitors/oracle.rb
@@ -87,50 +87,6 @@ module Arel # :nodoc: all
collector << " )"
end
- def visit_Arel_Nodes_In(o, collector)
- if Array === o.right && !o.right.empty?
- o.right.delete_if { |value| unboundable?(value) }
- end
-
- if Array === o.right && o.right.empty?
- collector << "1=0"
- else
- first = true
- o.right.each_slice(in_clause_length) do |sliced_o_right|
- collector << " OR " unless first
- first = false
-
- collector = visit o.left, collector
- collector << " IN ("
- visit(sliced_o_right, collector)
- collector << ")"
- end
- end
- collector
- end
-
- def visit_Arel_Nodes_NotIn(o, collector)
- if Array === o.right && !o.right.empty?
- o.right.delete_if { |value| unboundable?(value) }
- end
-
- if Array === o.right && o.right.empty?
- collector << "1=1"
- else
- first = true
- o.right.each_slice(in_clause_length) do |sliced_o_right|
- collector << " AND " unless first
- first = false
-
- collector = visit o.left, collector
- collector << " NOT IN ("
- visit(sliced_o_right, collector)
- collector << ")"
- end
- end
- collector
- end
-
def visit_Arel_Nodes_UpdateStatement(o, collector)
# Oracle does not allow ORDER BY/LIMIT in UPDATEs.
if o.orders.any? && o.limit.nil?
@@ -198,10 +154,6 @@ module Arel # :nodoc: all
collector = visit [o.left, o.right, 0, 1], collector
collector << ")"
end
-
- def in_clause_length
- 1000
- end
end
end
end
diff --git a/activerecord/lib/arel/visitors/oracle12.rb b/activerecord/lib/arel/visitors/oracle12.rb
index 8e0f07fca9..6269bc3907 100644
--- a/activerecord/lib/arel/visitors/oracle12.rb
+++ b/activerecord/lib/arel/visitors/oracle12.rb
@@ -8,11 +8,10 @@ module Arel # :nodoc: all
def visit_Arel_Nodes_SelectStatement(o, collector)
# Oracle does not allow LIMIT clause with select for update
if o.limit && o.lock
- raise ArgumentError, <<-MSG
- 'Combination of limit and lock is not supported.
- because generated SQL statements
- `SELECT FOR UPDATE and FETCH FIRST n ROWS` generates ORA-02014.`
- MSG
+ raise ArgumentError, <<~MSG
+ Combination of limit and lock is not supported. Because generated SQL statements
+ `SELECT FOR UPDATE and FETCH FIRST n ROWS` generates ORA-02014.
+ MSG
end
super
end
@@ -41,50 +40,6 @@ module Arel # :nodoc: all
collector << " )"
end
- def visit_Arel_Nodes_In(o, collector)
- if Array === o.right && !o.right.empty?
- o.right.delete_if { |value| unboundable?(value) }
- end
-
- if Array === o.right && o.right.empty?
- collector << "1=0"
- else
- first = true
- o.right.each_slice(in_clause_length) do |sliced_o_right|
- collector << " OR " unless first
- first = false
-
- collector = visit o.left, collector
- collector << " IN ("
- visit(sliced_o_right, collector)
- collector << ")"
- end
- end
- collector
- end
-
- def visit_Arel_Nodes_NotIn(o, collector)
- if Array === o.right && !o.right.empty?
- o.right.delete_if { |value| unboundable?(value) }
- end
-
- if Array === o.right && o.right.empty?
- collector << "1=1"
- else
- first = true
- o.right.each_slice(in_clause_length) do |sliced_o_right|
- collector << " AND " unless first
- first = false
-
- collector = visit o.left, collector
- collector << " NOT IN ("
- visit(sliced_o_right, collector)
- collector << ")"
- end
- end
- collector
- end
-
def visit_Arel_Nodes_UpdateStatement(o, collector)
# Oracle does not allow ORDER BY/LIMIT in UPDATEs.
if o.orders.any? && o.limit.nil?
@@ -106,10 +61,6 @@ module Arel # :nodoc: all
collector = visit [o.left, o.right, 0, 1], collector
collector << ")"
end
-
- def in_clause_length
- 1000
- end
end
end
end
diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb
index 277d553e6c..4740e6d94f 100644
--- a/activerecord/lib/arel/visitors/to_sql.rb
+++ b/activerecord/lib/arel/visitors/to_sql.rb
@@ -513,34 +513,66 @@ module Arel # :nodoc: all
end
def visit_Arel_Nodes_In(o, collector)
- if Array === o.right && !o.right.empty?
+ unless Array === o.right
+ return collect_in_clause(o.left, o.right, collector)
+ end
+
+ unless o.right.empty?
o.right.delete_if { |value| unboundable?(value) }
end
- if Array === o.right && o.right.empty?
- collector << "1=0"
+ return collector << "1=0" if o.right.empty?
+
+ in_clause_length = @connection.in_clause_length
+
+ if !in_clause_length || o.right.length <= in_clause_length
+ collect_in_clause(o.left, o.right, collector)
else
- collector = visit o.left, collector
- collector << " IN ("
- visit(o.right, collector) << ")"
+ collector << "("
+ o.right.each_slice(in_clause_length).each_with_index do |right, i|
+ collector << " OR " unless i == 0
+ collect_in_clause(o.left, right, collector)
+ end
+ collector << ")"
end
end
+ def collect_in_clause(left, right, collector)
+ collector = visit left, collector
+ collector << " IN ("
+ visit(right, collector) << ")"
+ end
+
def visit_Arel_Nodes_NotIn(o, collector)
- if Array === o.right && !o.right.empty?
+ unless Array === o.right
+ return collect_not_in_clause(o.left, o.right, collector)
+ end
+
+ unless o.right.empty?
o.right.delete_if { |value| unboundable?(value) }
end
- if Array === o.right && o.right.empty?
- collector << "1=1"
+ return collector << "1=1" if o.right.empty?
+
+ in_clause_length = @connection.in_clause_length
+
+ if !in_clause_length || o.right.length <= in_clause_length
+ collect_not_in_clause(o.left, o.right, collector)
else
- collector = visit o.left, collector
- collector << " NOT IN ("
- collector = visit o.right, collector
- collector << ")"
+ o.right.each_slice(in_clause_length).each_with_index do |right, i|
+ collector << " AND " unless i == 0
+ collect_not_in_clause(o.left, right, collector)
+ end
+ collector
end
end
+ def collect_not_in_clause(left, right, collector)
+ collector = visit left, collector
+ collector << " NOT IN ("
+ visit(right, collector) << ")"
+ end
+
def visit_Arel_Nodes_And(o, collector)
inject_join o.children, collector, " AND "
end