aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/associations/association_scope.rb24
-rw-r--r--activerecord/lib/active_record/attribute_methods/dirty.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb29
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/relation.rb7
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb7
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb4
-rw-r--r--activerecord/lib/active_record/relation/spawn_methods.rb5
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb5
-rw-r--r--activerecord/test/schema/mysql2_specific_schema.rb4
-rw-r--r--activerecord/test/schema/mysql_specific_schema.rb2
12 files changed, 71 insertions, 32 deletions
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb
index 982084c9b8..2972b7e13e 100644
--- a/activerecord/lib/active_record/associations/association_scope.rb
+++ b/activerecord/lib/active_record/associations/association_scope.rb
@@ -33,6 +33,23 @@ module ActiveRecord
private
+ def column_for(table_name, column_name)
+ columns = alias_tracker.connection.schema_cache.columns_hash[table_name]
+ columns[column_name]
+ end
+
+ def bind_value(scope, column, value)
+ substitute = alias_tracker.connection.substitute_at(
+ column, scope.bind_values.length)
+ scope.bind_values += [[column, value]]
+ substitute
+ end
+
+ def bind(scope, table_name, column_name, value)
+ column = column_for table_name, column_name
+ bind_value scope, column, value
+ end
+
def add_constraints(scope)
tables = construct_tables
@@ -67,10 +84,13 @@ module ActiveRecord
conditions = self.conditions[i]
if reflection == chain.last
- scope = scope.where(table[key].eq(owner[foreign_key]))
+ bind_val = bind scope, table.table_name, key.to_s, owner[foreign_key]
+ scope = scope.where(table[key].eq(bind_val))
if reflection.type
- scope = scope.where(table[reflection.type].eq(owner.class.base_class.name))
+ value = owner.class.base_class.name
+ bind_val = bind scope, table.table_name, reflection.type.to_s, value
+ scope = scope.where(table[reflection.type].eq(bind_val))
end
conditions.each do |condition|
diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index 433d508357..3a737e5b35 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -58,8 +58,6 @@ module ActiveRecord
@changed_attributes.delete(attr) unless _field_changed?(attr, old, value)
else
old = clone_attribute_value(:read_attribute, attr)
- # Save Time objects as TimeWithZone if time_zone_aware_attributes == true
- old = old.in_time_zone if clone_with_time_zone_conversion_attribute?(attr, old)
@changed_attributes[attr] = old if _field_changed?(attr, old, value)
end
@@ -92,10 +90,6 @@ module ActiveRecord
old != value
end
-
- def clone_with_time_zone_conversion_attribute?(attr, old)
- old.class.name == "Time" && time_zone_aware_attributes && !self.skip_time_zone_conversion_for_attributes.include?(attr.to_sym)
- end
end
end
end
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 db99c3fbef..174450eb00 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -20,14 +20,14 @@ module ActiveRecord
# Returns a record hash with the column names as keys and column values
# as values.
- def select_one(arel, name = nil)
- result = select_all(arel, name)
+ def select_one(arel, name = nil, binds = [])
+ result = select_all(arel, name, binds)
result.first if result
end
# Returns a single value from a record
- def select_value(arel, name = nil)
- if result = select_one(arel, name)
+ def select_value(arel, name = nil, binds = [])
+ if result = select_one(arel, name, binds)
result.values.first
end
end
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 eec7efadc2..e33903622b 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -484,15 +484,26 @@ module ActiveRecord
# Maps logical Rails types to MySQL-specific data types.
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
- return super unless type.to_s == 'integer'
-
- case limit
- when 1; 'tinyint'
- when 2; 'smallint'
- when 3; 'mediumint'
- when nil, 4, 11; 'int(11)' # compatibility with MySQL default
- when 5..8; 'bigint'
- else raise(ActiveRecordError, "No integer type has byte size #{limit}")
+ case type.to_s
+ when 'integer'
+ case limit
+ when 1; 'tinyint'
+ when 2; 'smallint'
+ when 3; 'mediumint'
+ when nil, 4, 11; 'int(11)' # compatibility with MySQL default
+ when 5..8; 'bigint'
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}")
+ end
+ when 'text'
+ case limit
+ when 0..0xff; 'tinytext'
+ when nil, 0x100..0xffff; 'text'
+ when 0x10000..0xffffff; 'mediumtext'
+ when 0x1000000..0xffffffff; 'longtext'
+ else raise(ActiveRecordError, "No text type has character length #{limit}")
+ end
+ else
+ super
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index c675b64a26..d2126a3e19 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -1189,7 +1189,7 @@ module ActiveRecord
# Construct a clean list of column names from the ORDER BY clause, removing
# any ASC/DESC modifiers
- order_columns = orders.collect { |s| s.gsub(/\s+(ASC|DESC)\s*/i, '') }
+ order_columns = orders.collect { |s| s.gsub(/\s+(ASC|DESC)\s*(NULLS\s+(FIRST|LAST)\s*)?/i, '') }
order_columns.delete_if { |c| c.blank? }
order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 3d1ca4f99b..7531e1fe6f 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -463,7 +463,12 @@ module ActiveRecord
node.left.relation.name == table_name
}
- Hash[equalities.map { |where| [where.left.name, where.right] }]
+ binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
+
+ Hash[equalities.map { |where|
+ name = where.left.name
+ [name, binds.fetch(name.to_s) { where.right }]
+ }]
end
def scope_for_create
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 63365e501b..510d01085d 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -183,7 +183,7 @@ module ActiveRecord
column_name = "#{table_name}.#{column_name}"
end
- result = klass.connection.select_all(select(column_name).arel)
+ result = klass.connection.select_all(select(column_name).arel, nil, bind_values)
types = result.column_types.merge klass.column_types
column = types[key]
@@ -254,7 +254,8 @@ module ActiveRecord
query_builder = relation.arel
end
- type_cast_calculated_value(@klass.connection.select_value(query_builder), column_for(column_name), operation)
+ result = @klass.connection.select_value(query_builder, nil, relation.bind_values)
+ type_cast_calculated_value(result, column_for(column_name), operation)
end
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
@@ -290,7 +291,7 @@ module ActiveRecord
relation = except(:group).group(group.join(','))
relation.select_values = select_values
- calculated_data = @klass.connection.select_all(relation)
+ calculated_data = @klass.connection.select_all(relation, nil, bind_values)
if association
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 26a5165abf..4cd703e0a5 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -200,7 +200,7 @@ module ActiveRecord
relation = relation.where(table[primary_key].eq(id)) if id
end
- connection.select_value(relation, "#{name} Exists") ? true : false
+ connection.select_value(relation, "#{name} Exists", relation.bind_values) ? true : false
end
protected
@@ -331,7 +331,7 @@ module ActiveRecord
substitute = connection.substitute_at(column, @bind_values.length)
relation = where(table[primary_key].eq(substitute))
- relation.bind_values = [[column, id]]
+ relation.bind_values += [[column, id]]
record = relation.first
unless record
diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb
index 706b0cd1cc..03ba8c8628 100644
--- a/activerecord/lib/active_record/relation/spawn_methods.rb
+++ b/activerecord/lib/active_record/relation/spawn_methods.rb
@@ -22,7 +22,7 @@ module ActiveRecord
end
end
- (Relation::MULTI_VALUE_METHODS - [:joins, :where, :order]).each do |method|
+ (Relation::MULTI_VALUE_METHODS - [:joins, :where, :order, :binds]).each do |method|
value = r.send(:"#{method}_values")
next if value.empty?
@@ -34,6 +34,8 @@ module ActiveRecord
merged_wheres = @where_values + r.where_values
+ merged_binds = (@bind_values + r.bind_values).uniq(&:first)
+
unless @where_values.empty?
# Remove duplicates, last one wins.
seen = Hash.new { |h,table| h[table] = {} }
@@ -50,6 +52,7 @@ module ActiveRecord
end
merged_relation.where_values = merged_wheres
+ merged_relation.bind_values = merged_binds
(Relation::SINGLE_VALUE_METHODS - [:lock, :create_with, :reordering]).each do |method|
value = r.send(:"#{method}_value")
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index 898d28456b..a71d0bb848 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -185,6 +185,11 @@ module ActiveRecord
assert_equal "(number > 100)", index.where
end
+ def test_distinct_with_nulls
+ assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls first"])
+ assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls last"])
+ end
+
private
def insert(ctx, data)
binds = data.map { |name, value|
diff --git a/activerecord/test/schema/mysql2_specific_schema.rb b/activerecord/test/schema/mysql2_specific_schema.rb
index ab2c7ccc10..65b6f9f227 100644
--- a/activerecord/test/schema/mysql2_specific_schema.rb
+++ b/activerecord/test/schema/mysql2_specific_schema.rb
@@ -1,5 +1,5 @@
ActiveRecord::Schema.define do
- create_table :binary_fields, :force => true, :options => 'CHARACTER SET latin1' do |t|
+ create_table :binary_fields, :force => true do |t|
t.binary :tiny_blob, :limit => 255
t.binary :normal_blob, :limit => 65535
t.binary :medium_blob, :limit => 16777215
@@ -32,4 +32,4 @@ CREATE TABLE collation_tests (
) CHARACTER SET utf8 COLLATE utf8_general_ci
SQL
-end \ No newline at end of file
+end
diff --git a/activerecord/test/schema/mysql_specific_schema.rb b/activerecord/test/schema/mysql_specific_schema.rb
index a0adfe3752..7d324f98c4 100644
--- a/activerecord/test/schema/mysql_specific_schema.rb
+++ b/activerecord/test/schema/mysql_specific_schema.rb
@@ -1,5 +1,5 @@
ActiveRecord::Schema.define do
- create_table :binary_fields, :force => true, :options => 'CHARACTER SET latin1' do |t|
+ create_table :binary_fields, :force => true do |t|
t.binary :tiny_blob, :limit => 255
t.binary :normal_blob, :limit => 65535
t.binary :medium_blob, :limit => 16777215