diff options
author | Aaron Patterson <tenderlove@github.com> | 2019-01-11 11:21:53 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-11 11:21:53 -0800 |
commit | 74bef0970fff60eaf5faefde30a23f3c36c0b3ee (patch) | |
tree | 628b6013130e0d2868b2afbac3f00f24629dbb9c /activerecord/lib | |
parent | 1e923b498492424ae627d7a2c61339148f887503 (diff) | |
parent | 3a1b2a21965c0cd7bcccff586ce04b029eb4c359 (diff) | |
download | rails-74bef0970fff60eaf5faefde30a23f3c36c0b3ee.tar.gz rails-74bef0970fff60eaf5faefde30a23f3c36c0b3ee.tar.bz2 rails-74bef0970fff60eaf5faefde30a23f3c36c0b3ee.zip |
Merge branch 'master' into ac_params_exists
Diffstat (limited to 'activerecord/lib')
16 files changed, 67 insertions, 81 deletions
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 2299fc0214..79d71bfb5d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -123,7 +123,7 @@ module ActiveRecord # +binds+ as the bind substitutes. +name+ is logged along with # the executed +sql+ statement. def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil) - sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds) + sql, binds = sql_for_insert(sql, pk, sequence_name, binds) exec_query(sql, name, binds) end @@ -464,7 +464,7 @@ module ActiveRecord exec_query(sql, name, binds, prepare: true) end - def sql_for_insert(sql, pk, id_value, sequence_name, binds) + def sql_for_insert(sql, pk, sequence_name, binds) [sql, binds] end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 346d4b067a..0d2d66f919 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -504,15 +504,17 @@ module ActiveRecord @connection end - def case_sensitive_comparison(table, attribute, column, value) # :nodoc: - table[attribute].eq(value) + def case_sensitive_comparison(attribute, value) # :nodoc: + attribute.eq(value) end - def case_insensitive_comparison(table, attribute, column, value) # :nodoc: + def case_insensitive_comparison(attribute, value) # :nodoc: + column = column_for_attribute(attribute) + if can_perform_case_insensitive_comparison_for?(column) - table[attribute].lower.eq(table.lower(value)) + attribute.lower.eq(attribute.relation.lower(value)) else - table[attribute].eq(value) + attribute.eq(value) end end @@ -659,6 +661,11 @@ module ActiveRecord raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}") end + def column_for_attribute(attribute) + table_name = attribute.relation.name + schema_cache.columns_hash(table_name)[attribute.name.to_s] + end + def collector if prepared_statements Arel::Collectors::Composite.new( diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 10961ed9c8..70d281b62b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -476,9 +476,11 @@ module ActiveRecord SQL end - def case_sensitive_comparison(table, attribute, column, value) # :nodoc: + def case_sensitive_comparison(attribute, value) # :nodoc: + column = column_for_attribute(attribute) + if column.collation && !column.case_sensitive? - table[attribute].eq(Arel::Nodes::Bin.new(value)) + attribute.eq(Arel::Nodes::Bin.new(value)) else super end @@ -579,13 +581,13 @@ module ActiveRecord m.alias_type %r(bit)i, "binary" m.register_type(%r(enum)i) do |sql_type| - limit = sql_type[/^enum\((.+)\)/i, 1] + limit = sql_type[/^enum\s*\((.+)\)/i, 1] .split(",").map { |enum| enum.strip.length - 2 }.max MysqlString.new(limit: limit) end m.register_type(%r(^set)i) do |sql_type| - limit = sql_type[/^set\((.+)\)/i, 1] + limit = sql_type[/^set\s*\((.+)\)/i, 1] .split(",").map { |set| set.strip.length - 1 }.sum - 1 MysqlString.new(limit: limit) end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb index c70a4fa875..41633872e2 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb @@ -110,7 +110,7 @@ module ActiveRecord end alias :exec_update :exec_delete - def sql_for_insert(sql, pk, id_value, sequence_name, binds) # :nodoc: + def sql_for_insert(sql, pk, sequence_name, binds) # :nodoc: if pk.nil? # Extract the table from the insert sql. Yuck. table_ref = extract_table_ref_from_insert_sql(sql) 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 16260fe565..3516bef75a 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -22,8 +22,8 @@ module ActiveRecord def create_database(name, options = {}) options = { encoding: "utf8" }.merge!(options.symbolize_keys) - option_string = options.inject("") do |memo, (key, value)| - memo += case key + option_string = options.each_with_object(+"") do |(key, value), memo| + memo << case key when :owner " OWNER = \"#{value}\"" when :template diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index ba221a333b..a863227276 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -44,6 +44,11 @@ module ActiveRecord end def bind_attribute(name, value) # :nodoc: + if reflection = klass._reflect_on_association(name) + name = reflection.foreign_key + value = value.read_attribute(reflection.klass.primary_key) unless value.nil? + end + attr = arel_attribute(name) bind = predicate_builder.build_bind_attribute(attr.name, value) yield attr, bind diff --git a/activerecord/lib/active_record/relation/predicate_builder/range_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/range_handler.rb index 44bb2c7ab6..2ea27c8490 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/range_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/range_handler.rb @@ -3,11 +3,7 @@ module ActiveRecord class PredicateBuilder class RangeHandler # :nodoc: - class RangeWithBinds < Struct.new(:begin, :end) - def exclude_end? - false - end - end + RangeWithBinds = Struct.new(:begin, :end, :exclude_end?) def initialize(predicate_builder) @predicate_builder = predicate_builder @@ -16,22 +12,7 @@ module ActiveRecord def call(attribute, value) begin_bind = predicate_builder.build_bind_attribute(attribute.name, value.begin) end_bind = predicate_builder.build_bind_attribute(attribute.name, value.end) - - if begin_bind.value.infinity? - if end_bind.value.infinity? - attribute.not_in([]) - elsif value.exclude_end? - attribute.lt(end_bind) - else - attribute.lteq(end_bind) - end - elsif end_bind.value.infinity? - attribute.gteq(begin_bind) - elsif value.exclude_end? - attribute.gteq(begin_bind).and(attribute.lt(end_bind)) - else - attribute.between(RangeWithBinds.new(begin_bind, end_bind)) - end + attribute.between(RangeWithBinds.new(begin_bind, end_bind, value.exclude_end?)) end private diff --git a/activerecord/lib/active_record/relation/query_attribute.rb b/activerecord/lib/active_record/relation/query_attribute.rb index f64bd30d38..b45326bdda 100644 --- a/activerecord/lib/active_record/relation/query_attribute.rb +++ b/activerecord/lib/active_record/relation/query_attribute.rb @@ -30,12 +30,12 @@ module ActiveRecord @_boundable = false end - def infinity? - _infinity?(value_before_type_cast) || boundable? && _infinity?(value_for_database) + def infinite? + infinity?(value_before_type_cast) || boundable? && infinity?(value_for_database) end private - def _infinity?(value) + def infinity?(value) value.respond_to?(:infinite?) && value.infinite? end end diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index d32f971ad1..e19077eb88 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -56,7 +56,7 @@ module ActiveRecord def touch_attributes_with_time(*names, time: nil) attribute_names = timestamp_attributes_for_update_in_model attribute_names |= names.map(&:to_s) - attribute_names.index_with(time ||= current_time_from_proper_timezone) + attribute_names.index_with(time || current_time_from_proper_timezone) end private diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 5a1dbc8e53..111b6c9a64 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -56,33 +56,21 @@ module ActiveRecord end def build_relation(klass, attribute, value) - if reflection = klass._reflect_on_association(attribute) - attribute = reflection.foreign_key - value = value.attributes[reflection.klass.primary_key] unless value.nil? - end - - if value.nil? - return klass.unscoped.where!(attribute => value) - end - - # the attribute may be an aliased attribute - if klass.attribute_alias?(attribute) - attribute = klass.attribute_alias(attribute) + relation = klass.unscoped + comparison = relation.bind_attribute(attribute, value) do |attr, bind| + return relation.none! unless bind.boundable? + + if bind.nil? + attr.eq(bind) + elsif options[:case_sensitive] + klass.connection.case_sensitive_comparison(attr, bind) + else + # will use SQL LOWER function before comparison, unless it detects a case insensitive collation + klass.connection.case_insensitive_comparison(attr, bind) + end end - attribute_name = attribute.to_s - value = klass.predicate_builder.build_bind_attribute(attribute_name, value) - - table = klass.arel_table - column = klass.columns_hash[attribute_name] - - comparison = if !options[:case_sensitive] - # will use SQL LOWER function before comparison, unless it detects a case insensitive collation - klass.connection.case_insensitive_comparison(table, attribute, column, value) - else - klass.connection.case_sensitive_comparison(table, attribute, column, value) - end - klass.unscoped.where!(comparison) + relation.where!(comparison) end def scope_relation(record, relation) diff --git a/activerecord/lib/arel/nodes/bind_param.rb b/activerecord/lib/arel/nodes/bind_param.rb index ba8340558a..f145e44ae3 100644 --- a/activerecord/lib/arel/nodes/bind_param.rb +++ b/activerecord/lib/arel/nodes/bind_param.rb @@ -24,6 +24,10 @@ module Arel # :nodoc: all value.nil? end + def infinite? + value.respond_to?(:infinite?) && value.infinite? + end + def boundable? !value.respond_to?(:boundable?) || value.boundable? end diff --git a/activerecord/lib/arel/nodes/casted.rb b/activerecord/lib/arel/nodes/casted.rb index c1e6e97d6d..6e911b717d 100644 --- a/activerecord/lib/arel/nodes/casted.rb +++ b/activerecord/lib/arel/nodes/casted.rb @@ -27,6 +27,10 @@ module Arel # :nodoc: all class Quoted < Arel::Nodes::Unary # :nodoc: alias :val :value def nil?; val.nil?; end + + def infinite? + value.respond_to?(:infinite?) && value.infinite? + end end def self.build_quoted(other, attribute = nil) diff --git a/activerecord/lib/arel/predications.rb b/activerecord/lib/arel/predications.rb index 77502dd199..0c03e93138 100644 --- a/activerecord/lib/arel/predications.rb +++ b/activerecord/lib/arel/predications.rb @@ -35,15 +35,15 @@ module Arel # :nodoc: all end def between(other) - if equals_quoted?(other.begin, -Float::INFINITY) - if equals_quoted?(other.end, Float::INFINITY) + if infinity?(other.begin) + if other.end.nil? || infinity?(other.end) not_in([]) elsif other.exclude_end? lt(other.end) else lteq(other.end) end - elsif equals_quoted?(other.end, Float::INFINITY) + elsif other.end.nil? || infinity?(other.end) gteq(other.begin) elsif other.exclude_end? gteq(other.begin).and(lt(other.end)) @@ -81,15 +81,15 @@ Passing a range to `#in` is deprecated. Call `#between`, instead. end def not_between(other) - if equals_quoted?(other.begin, -Float::INFINITY) - if equals_quoted?(other.end, Float::INFINITY) + if infinity?(other.begin) + if infinity?(other.end) self.in([]) elsif other.exclude_end? gteq(other.end) else gt(other.end) end - elsif equals_quoted?(other.end, Float::INFINITY) + elsif infinity?(other.end) lt(other.begin) else left = lt(other.begin) @@ -238,12 +238,8 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead. others.map { |v| quoted_node(v) } end - def equals_quoted?(maybe_quoted, value) - if maybe_quoted.is_a?(Nodes::Quoted) - maybe_quoted.val == value - else - maybe_quoted == value - end + def infinity?(value) + value.respond_to?(:infinite?) && value.infinite? end end end diff --git a/activerecord/lib/arel/visitors/informix.rb b/activerecord/lib/arel/visitors/informix.rb index 0a9713794e..208fa15aef 100644 --- a/activerecord/lib/arel/visitors/informix.rb +++ b/activerecord/lib/arel/visitors/informix.rb @@ -15,8 +15,9 @@ module Arel # :nodoc: all collector << "ORDER BY " collector = inject_join o.orders, collector, ", " end - collector = maybe_visit o.lock, collector + maybe_visit o.lock, collector end + def visit_Arel_Nodes_SelectCore(o, collector) collector = inject_join o.projections, collector, ", " if o.source && !o.source.empty? diff --git a/activerecord/lib/arel/visitors/oracle12.rb b/activerecord/lib/arel/visitors/oracle12.rb index b092aa95e0..9a7fe4d626 100644 --- a/activerecord/lib/arel/visitors/oracle12.rb +++ b/activerecord/lib/arel/visitors/oracle12.rb @@ -20,7 +20,7 @@ module Arel # :nodoc: all def visit_Arel_Nodes_SelectOptions(o, collector) collector = maybe_visit o.offset, collector collector = maybe_visit o.limit, collector - collector = maybe_visit o.lock, collector + maybe_visit o.lock, collector end def visit_Arel_Nodes_Limit(o, collector) diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb index f9fe4404eb..b5a960ce68 100644 --- a/activerecord/lib/arel/visitors/to_sql.rb +++ b/activerecord/lib/arel/visitors/to_sql.rb @@ -208,14 +208,12 @@ module Arel # :nodoc: all end visit_Arel_Nodes_SelectOptions(o, collector) - - collector end def visit_Arel_Nodes_SelectOptions(o, collector) collector = maybe_visit o.limit, collector collector = maybe_visit o.offset, collector - collector = maybe_visit o.lock, collector + maybe_visit o.lock, collector end def visit_Arel_Nodes_SelectCore(o, collector) |